blob: dcdcf6130e9b490cfbfb4af9e4096a02fdb94edc [file] [log] [blame]
// -*- c-basic-offset: 2 -*-
/*
* Copyright (C) 2000 Harri Porten (porten@kde.org)
* Copyright (c) 2000 Daniel Molkentin (molkentin@kde.org)
* Copyright (c) 2000 Stefan Schimanski (schimmi@kde.org)
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "kjs_navigator.h"
#include "AtomicString.h"
#include "CookieJar.h"
#include "DOMWindow.h"
#include "Document.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "Language.h"
#include "Page.h"
#include "PluginInfoStore.h"
#include "Settings.h"
#include "kjs_window.h"
#include <kjs/object_object.h>
#ifndef WEBCORE_NAVIGATOR_PLATFORM
#if PLATFORM(MAC) && PLATFORM(PPC)
#define WEBCORE_NAVIGATOR_PLATFORM "MacPPC"
#elif PLATFORM(MAC) && PLATFORM(X86)
#define WEBCORE_NAVIGATOR_PLATFORM "MacIntel"
#elif PLATFORM(WIN_OS)
#define WEBCORE_NAVIGATOR_PLATFORM "Win32"
#else
#define WEBCORE_NAVIGATOR_PLATFORM ""
#endif
#endif // ifndef WEBCORE_NAVIGATOR_PLATFORM
#ifndef WEBCORE_NAVIGATOR_PRODUCT
#define WEBCORE_NAVIGATOR_PRODUCT "Gecko"
#endif // ifndef WEBCORE_NAVIGATOR_PRODUCT
#ifndef WEBCORE_NAVIGATOR_PRODUCT_SUB
#define WEBCORE_NAVIGATOR_PRODUCT_SUB "20030107"
#endif // ifndef WEBCORE_NAVIGATOR_PRODUCT_SUB
#ifndef WEBCORE_NAVIGATOR_VENDOR
#define WEBCORE_NAVIGATOR_VENDOR "Apple Computer, Inc."
#endif // ifndef WEBCORE_NAVIGATOR_VENDOR
#ifndef WEBCORE_NAVIGATOR_VENDOR_SUB
#define WEBCORE_NAVIGATOR_VENDOR_SUB ""
#endif // ifndef WEBCORE_NAVIGATOR_VENDOR_SUB
using namespace WebCore;
namespace KJS {
class PluginBase : public DOMObject {
public:
PluginBase(ExecState *exec);
virtual ~PluginBase();
static void refresh(bool reload);
protected:
static void cachePluginDataIfNecessary();
static Vector<PluginInfo*> *plugins;
static Vector<MimeClassInfo*> *mimes;
private:
static int m_plugInCacheRefCount;
};
class Plugins : public PluginBase {
public:
Plugins(ExecState *exec) : PluginBase(exec) {};
virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
JSValue *getValueProperty(ExecState *, int token) const;
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
enum { Length };
private:
static JSValue *indexGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
static JSValue *nameGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
};
JSValue* pluginsFunctionRefresh(ExecState*, JSObject*, const List&);
class MimeTypes : public PluginBase {
public:
MimeTypes(ExecState *exec) : PluginBase(exec) { };
virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
JSValue *getValueProperty(ExecState *, int token) const;
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
enum { Length };
private:
static JSValue *indexGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
static JSValue *nameGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
};
class Plugin : public PluginBase {
public:
Plugin(ExecState *exec, PluginInfo *info) : PluginBase(exec), m_info(info) { }
virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
JSValue *getValueProperty(ExecState *, int token) const;
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
enum { Name, Filename, Description, Length };
private:
static JSValue *indexGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
static JSValue *nameGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
PluginInfo *m_info;
};
class MimeType : public PluginBase {
public:
MimeType( ExecState *exec, MimeClassInfo *info ) : PluginBase(exec), m_info(info) { }
virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
JSValue *getValueProperty(ExecState *, int token) const;
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
enum { Type, Suffixes, Description, EnabledPlugin };
private:
MimeClassInfo *m_info;
};
} // namespace
#include "kjs_navigator.lut.h"
namespace KJS {
const ClassInfo Plugins::info = { "PluginArray", 0, &PluginsTable };
const ClassInfo MimeTypes::info = { "MimeTypeArray", 0, &MimeTypesTable };
const ClassInfo Plugin::info = { "Plugin", 0, &PluginTable };
const ClassInfo MimeType::info = { "MimeType", 0, &MimeTypeTable };
Vector<PluginInfo*> *KJS::PluginBase::plugins = 0;
Vector<MimeClassInfo*> *KJS::PluginBase::mimes = 0;
int KJS::PluginBase::m_plugInCacheRefCount = 0;
const ClassInfo Navigator::info = { "Navigator", 0, &NavigatorTable };
/*
@begin NavigatorTable 13
appCodeName Navigator::AppCodeName DontDelete|ReadOnly
appName Navigator::AppName DontDelete|ReadOnly
appVersion Navigator::AppVersion DontDelete|ReadOnly
language Navigator::Language DontDelete|ReadOnly
userAgent Navigator::UserAgent DontDelete|ReadOnly
platform Navigator::Platform DontDelete|ReadOnly
plugins Navigator::_Plugins DontDelete|ReadOnly
mimeTypes Navigator::_MimeTypes DontDelete|ReadOnly
product Navigator::Product DontDelete|ReadOnly
productSub Navigator::ProductSub DontDelete|ReadOnly
vendor Navigator::Vendor DontDelete|ReadOnly
vendorSub Navigator::VendorSub DontDelete|ReadOnly
cookieEnabled Navigator::CookieEnabled DontDelete|ReadOnly
javaEnabled navigatorProtoFuncJavaEnabled DontDelete|Function 0
@end
*/
Navigator::Navigator(JSObject* prototype, Frame* frame)
: DOMObject(prototype)
, m_frame(frame)
{
}
bool Navigator::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
{
return getStaticPropertySlot<Navigator, JSObject>(exec, &NavigatorTable, this, propertyName, slot);
}
static bool needsYouTubeQuirk(ExecState*, Frame*);
#if !PLATFORM(WIN)
static inline bool needsYouTubeQuirk(ExecState*, Frame*)
{
return false;
}
#else
static bool needsYouTubeQuirk(ExecState* exec, Frame* frame)
{
// This quirk works around a mistaken check in an ad at youtube.com.
// There's a function called isSafari that returns false if the function
// called isWindows returns true; thus the site malfunctions with Windows Safari.
// Do the quirk only if the function's name is "isWindows".
FunctionImp* function = exec->function();
if (!function)
return false;
static const Identifier& isWindowsFunctionName = *new Identifier("isWindows");
if (function->functionName() != isWindowsFunctionName)
return false;
// Do the quirk only if the function is called by an "isSafari" function.
// However, that function is not itself named -- it is stored in the isSafari
// property, though, so that's how recognize it.
ExecState* callingExec = exec->callingExecState();
if (!callingExec)
return false;
FunctionImp* callingFunction = callingExec->function();
if (!callingFunction)
return false;
JSObject* thisObject = callingExec->thisValue();
if (!thisObject)
return false;
static const Identifier& isSafariFunctionName = *new Identifier("isSafari");
JSValue* isSafariFunction = thisObject->getDirect(isSafariFunctionName);
if (isSafariFunction != callingFunction)
return false;
// FIXME: The document is never null, so we should remove this check along with the
// other similar ones in this file when we are absolutely sure it's safe.
Document* document = frame->document();
if (!document)
return false;
// Do the quirk only on the front page of the global version of YouTube.
const KURL& url = document->url();
if (url.host() != "youtube.com" && url.host() != "www.youtube.com")
return false;
if (url.path() != "/")
return false;
// As with other site-specific quirks, allow website developers to turn this off.
// In theory, this allows website developers to check if their fixes are effective.
Settings* settings = frame->settings();
if (!settings)
return false;
if (!settings->needsSiteSpecificQuirks())
return false;
return true;
}
#endif
JSValue* Navigator::getValueProperty(ExecState* exec, int token) const
{
switch (token) {
case AppCodeName:
return jsString("Mozilla");
case AppName:
return jsString("Netscape");
case AppVersion: {
if (needsYouTubeQuirk(exec, m_frame))
return jsString("");
// Version is everything in the user agent string past the "Mozilla/" prefix.
const String userAgent = m_frame->loader()->userAgent(m_frame->document() ? m_frame->document()->url() : KURL());
return jsString(userAgent.substring(userAgent.find('/') + 1));
}
case Product:
return jsString(WEBCORE_NAVIGATOR_PRODUCT);
case ProductSub:
return jsString(WEBCORE_NAVIGATOR_PRODUCT_SUB);
case Vendor:
return jsString(WEBCORE_NAVIGATOR_VENDOR);
case VendorSub:
return jsString(WEBCORE_NAVIGATOR_VENDOR_SUB);
case Language:
return jsString(defaultLanguage());
case UserAgent:
return jsString(m_frame->loader()->userAgent(m_frame->document() ? m_frame->document()->url() : KURL()));
case Platform:
return jsString(WEBCORE_NAVIGATOR_PLATFORM);
case _Plugins:
return new Plugins(exec);
case _MimeTypes:
return new MimeTypes(exec);
case CookieEnabled:
return jsBoolean(cookiesEnabled(m_frame->document()));
}
return 0;
}
/*******************************************************************/
void PluginBase::cachePluginDataIfNecessary()
{
if (!plugins) {
plugins = new Vector<PluginInfo*>;
mimes = new Vector<MimeClassInfo*>;
// read configuration
PluginInfoStore c;
unsigned pluginCount = c.pluginCount();
for (unsigned n = 0; n < pluginCount; n++) {
PluginInfo* plugin = c.createPluginInfoForPluginAtIndex(n);
if (!plugin)
continue;
plugins->append(plugin);
if (plugin->mimes.isEmpty())
continue;
Vector<MimeClassInfo*>::iterator end = plugin->mimes.end();
for (Vector<MimeClassInfo*>::iterator itr = plugin->mimes.begin(); itr != end; itr++)
mimes->append(*itr);
}
}
}
PluginBase::PluginBase(ExecState* exec)
: DOMObject(exec->lexicalGlobalObject()->objectPrototype())
{
cachePluginDataIfNecessary();
m_plugInCacheRefCount++;
}
PluginBase::~PluginBase()
{
m_plugInCacheRefCount--;
if (!m_plugInCacheRefCount) {
if (plugins) {
deleteAllValues(*plugins);
delete plugins;
plugins = 0;
}
if (mimes) {
deleteAllValues(*mimes);
delete mimes;
mimes = 0;
}
}
}
void PluginBase::refresh(bool reload)
{
if (plugins) {
deleteAllValues(*plugins);
delete plugins;
plugins = 0;
}
if (mimes) {
deleteAllValues(*mimes);
delete mimes;
mimes = 0;
}
refreshPlugins(reload);
cachePluginDataIfNecessary();
}
/*******************************************************************/
/*
@begin PluginsTable 2
length Plugins::Length DontDelete|ReadOnly
refresh pluginsFunctionRefresh DontDelete|Function 0
@end
*/
JSValue *Plugins::getValueProperty(ExecState *exec, int token) const
{
ASSERT(token == Length);
return jsNumber(plugins->size());
}
JSValue *Plugins::indexGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
{
return new Plugin(exec, plugins->at(slot.index()));
}
JSValue *Plugins::nameGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
{
AtomicString atomicPropertyName = propertyName;
Vector<PluginInfo*>::iterator end = plugins->end();
for (Vector<PluginInfo*>::iterator itr = plugins->begin(); itr != end; itr++) {
PluginInfo *pl = *itr;
if (pl->name == atomicPropertyName)
return new Plugin(exec, pl);
}
return jsUndefined();
}
bool Plugins::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
{
const HashEntry* entry = Lookup::findEntry(&PluginsTable, propertyName);
if (entry) {
if (entry->attr & Function)
slot.setStaticEntry(this, entry, staticFunctionGetter);
else
slot.setStaticEntry(this, entry, staticValueGetter<Plugins>);
return true;
} else {
// plugins[#]
bool ok;
unsigned int i = propertyName.toUInt32(&ok);
if (ok && i < plugins->size()) {
slot.setCustomIndex(this, i, indexGetter);
return true;
}
// plugin[name]
AtomicString atomicPropertyName = propertyName;
Vector<PluginInfo*>::iterator end = plugins->end();
for (Vector<PluginInfo*>::iterator itr = plugins->begin(); itr != end; itr++) {
if ((*itr)->name == atomicPropertyName) {
slot.setCustom(this, nameGetter);
return true;
}
}
}
return PluginBase::getOwnPropertySlot(exec, propertyName, slot);
}
/*******************************************************************/
/*
@begin MimeTypesTable 1
length MimeTypes::Length DontDelete|ReadOnly
@end
*/
JSValue *MimeTypes::getValueProperty(ExecState *exec, int token) const
{
ASSERT(token == Length);
return jsNumber(mimes->size());
}
JSValue *MimeTypes::indexGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
{
return new MimeType(exec, mimes->at(slot.index()));
}
JSValue *MimeTypes::nameGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
{
AtomicString atomicPropertyName = propertyName;
Vector<MimeClassInfo*>::iterator end = mimes->end();
for (Vector<MimeClassInfo*>::iterator itr = mimes->begin(); itr != end; itr++) {
MimeClassInfo *m = (*itr);
if (m->type == atomicPropertyName)
return new MimeType(exec, m);
}
return jsUndefined();
}
bool MimeTypes::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
{
const HashEntry* entry = Lookup::findEntry(&MimeTypesTable, propertyName);
if (entry) {
slot.setStaticEntry(this, entry, staticValueGetter<MimeTypes>);
return true;
} else {
// mimeTypes[#]
bool ok;
unsigned int i = propertyName.toUInt32(&ok);
if (ok && i < mimes->size()) {
slot.setCustomIndex(this, i, indexGetter);
return true;
}
// mimeTypes[name]
AtomicString atomicPropertyName = propertyName;
Vector<MimeClassInfo*>::iterator end = mimes->end();
for (Vector<MimeClassInfo*>::iterator itr = mimes->begin(); itr != end; itr++) {
if ((*itr)->type == atomicPropertyName) {
slot.setCustom(this, nameGetter);
return true;
}
}
}
return PluginBase::getOwnPropertySlot(exec, propertyName, slot);
}
/************************************************************************/
/*
@begin PluginTable 4
name Plugin::Name DontDelete|ReadOnly
filename Plugin::Filename DontDelete|ReadOnly
description Plugin::Description DontDelete|ReadOnly
length Plugin::Length DontDelete|ReadOnly
@end
*/
JSValue *Plugin::getValueProperty(ExecState *exec, int token) const
{
switch (token) {
case Name:
return jsString(m_info->name);
case Filename:
return jsString(m_info->file);
case Description:
return jsString(m_info->desc);
case Length:
return jsNumber(m_info->mimes.size());
default:
ASSERT(0);
return jsUndefined();
}
}
JSValue *Plugin::indexGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
{
Plugin *thisObj = static_cast<Plugin *>(slot.slotBase());
return new MimeType(exec, thisObj->m_info->mimes.at(slot.index()));
}
JSValue *Plugin::nameGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
{
Plugin *thisObj = static_cast<Plugin *>(slot.slotBase());
AtomicString atomicPropertyName = propertyName;
Vector<MimeClassInfo*>::iterator end = thisObj->m_info->mimes.end();
for (Vector<MimeClassInfo*>::iterator itr = thisObj->m_info->mimes.begin(); itr != end; itr++) {
MimeClassInfo *m = (*itr);
if (m->type == atomicPropertyName)
return new MimeType(exec, m);
}
return jsUndefined();
}
bool Plugin::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
{
const HashEntry* entry = Lookup::findEntry(&PluginTable, propertyName);
if (entry) {
slot.setStaticEntry(this, entry, staticValueGetter<Plugin>);
return true;
} else {
// plugin[#]
bool ok;
unsigned int i = propertyName.toUInt32(&ok);
if (ok && i < m_info->mimes.size()) {
slot.setCustomIndex(this, i, indexGetter);
return true;
}
// plugin["name"]
AtomicString atomicPropertyName = propertyName;
Vector<MimeClassInfo*>::iterator end = m_info->mimes.end();
for (Vector<MimeClassInfo*>::iterator itr = m_info->mimes.begin(); itr != end; itr++) {
if ((*itr)->type == atomicPropertyName) {
slot.setCustom(this, nameGetter);
return true;
}
}
}
return PluginBase::getOwnPropertySlot(exec, propertyName, slot);
}
/*****************************************************************************/
/*
@begin MimeTypeTable 4
type MimeType::Type DontDelete|ReadOnly
suffixes MimeType::Suffixes DontDelete|ReadOnly
description MimeType::Description DontDelete|ReadOnly
enabledPlugin MimeType::EnabledPlugin DontDelete|ReadOnly
@end
*/
JSValue *MimeType::getValueProperty(ExecState *exec, int token) const
{
switch (token) {
case Type:
return jsString(m_info->type);
case Suffixes:
return jsString(m_info->suffixes);
case Description:
return jsString(m_info->desc);
case EnabledPlugin: {
Frame* frame = Window::retrieveActive(exec)->impl()->frame();
ASSERT(frame);
Settings* settings = frame->settings();
if (settings && settings->arePluginsEnabled())
return new Plugin(exec, m_info->plugin);
else
return jsUndefined();
}
default:
return jsUndefined();
}
}
bool MimeType::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
{
return getStaticValueSlot<MimeType, PluginBase>(exec, &MimeTypeTable, this, propertyName, slot);
}
JSValue* pluginsFunctionRefresh(ExecState* exec, JSObject*, const List& args)
{
PluginBase::refresh(args[0]->toBoolean(exec));
return jsUndefined();
}
JSValue* navigatorProtoFuncJavaEnabled(ExecState* exec, JSObject* thisObj, const List&)
{
if (!thisObj->inherits(&KJS::Navigator::info))
return throwError(exec, TypeError);
Navigator *nav = static_cast<Navigator *>(thisObj);
// javaEnabled()
Settings* settings = nav->frame() ? nav->frame()->settings() : 0;
return jsBoolean(settings && settings->isJavaEnabled());
}
} // namespace