From 9044153cb63835e39b9de8ec4ade237c03e3888a Mon Sep 17 00:00:00 2001 From: Michael Schutte Date: Wed, 28 Dec 2011 20:43:04 +0100 Subject: [PATCH] Import 1.0rc1 supporting Firefox up to 11.* --- .hg_archival.txt | 4 + .hgignore | 9 + .hgsub | 1 + .hgsubstate | 1 + BREAKING_CHANGES | 3 +- LICENSE.txt | 6 +- binary/chrome.manifest | 8 + binary/config.mk | 39 + binary/install.rdf | 35 + binary/src/Makefile | 111 ++ binary/src/config.h | 2 + binary/src/dactylIUtils.idl | 38 + binary/src/dactylModule.cpp | 42 + binary/src/dactylUtils.cpp | 381 ++++ binary/src/dactylUtils.h | 36 + binary/src/mozJSLoaderUtils.cpp | 196 ++ binary/src/mozJSLoaderUtils.h | 88 + binary/src/subscriptLoader.cpp | 583 ++++++ common/Makefile | 27 +- common/bootstrap.js | 132 +- common/chrome.manifest | 9 +- common/components/commandline-handler.js | 63 +- common/components/protocols.js | 385 ---- common/config.json | 38 + common/content/abbreviations.js | 6 +- common/content/about.xul | 2 +- common/content/autocommands.js | 62 +- common/content/bindings.xml | 8 + common/content/bookmarks.js | 163 +- common/content/browser.js | 56 +- common/content/commandline.js | 1361 +++++++++----- common/content/dactyl.js | 966 ++++------ common/content/disable-acr.jsm | 6 +- common/content/editor.js | 1404 ++++++++++----- common/content/events.js | 1113 +++--------- common/content/help.js | 2 +- common/content/help.xsl | 32 +- common/content/hints.js | 111 +- common/content/history.js | 212 ++- common/content/key-processors.js | 324 ++++ common/content/mappings.js | 125 +- common/content/marks.js | 176 +- common/content/modes.js | 225 ++- common/content/mow.js | 102 +- common/content/quickmarks.js | 8 +- common/content/statusline.js | 23 +- common/content/tabs.js | 419 +++-- common/javascript.vim | 343 ---- common/locale/en-US/all.xml | 1 + common/locale/en-US/autocommands.xml | 4 +- common/locale/en-US/browsing.xml | 234 ++- common/locale/en-US/buffer.xml | 26 +- common/locale/en-US/cmdline.xml | 33 +- common/locale/en-US/developer.xml | 2 +- common/locale/en-US/faq.xml | 10 +- common/locale/en-US/gui.xml | 2 +- common/locale/en-US/hints.xml | 4 +- common/locale/en-US/index.xml | 2 + common/locale/en-US/map.xml | 127 +- common/locale/en-US/marks.xml | 132 +- common/locale/en-US/messages.properties | 38 +- common/locale/en-US/options.xml | 203 ++- common/locale/en-US/pattern.xml | 34 +- common/locale/en-US/privacy.xml | 28 +- common/locale/en-US/repeat.xml | 5 +- common/locale/en-US/starting.xml | 28 +- common/locale/en-US/styling.xml | 2 +- common/locale/en-US/tabs.xml | 55 +- common/locale/en-US/various.xml | 14 +- common/modules/addons.jsm | 47 +- common/modules/base.jsm | 296 ++- common/modules/bookmarkcache.jsm | 80 +- common/modules/bootstrap.jsm | 33 +- .../{content/buffer.js => modules/buffer.jsm} | 1476 ++++++++++----- common/modules/cache.jsm | 262 +++ common/modules/commands.jsm | 240 ++- common/modules/completion.jsm | 205 ++- common/modules/config.jsm | 897 +++------- common/modules/contexts.jsm | 182 +- common/modules/dom.jsm | 1589 +++++++++++++++++ common/modules/downloads.jsm | 36 +- common/modules/finder.jsm | 316 ++-- common/modules/help.jsm | 467 +++++ common/modules/highlight.jsm | 16 +- common/modules/io.jsm | 196 +- common/modules/javascript.jsm | 33 +- common/modules/main.jsm | 357 ++++ common/modules/messages.jsm | 117 +- common/modules/options.jsm | 209 ++- common/modules/overlay.jsm | 633 ++++--- common/modules/prefs.jsm | 23 +- common/modules/protocol.jsm | 255 +++ common/modules/sanitizer.jsm | 87 +- common/modules/services.jsm | 102 +- common/modules/storage.jsm | 179 +- common/modules/styles.jsm | 57 +- common/modules/template.jsm | 68 +- common/modules/util.jsm | 1026 +++-------- common/process_manifest.awk | 3 +- common/skin/dactyl.css | 32 +- common/skin/global-styles.css | 321 ++++ common/skin/help-styles.css | 215 +++ common/tests/functional/testDOMEvents.js | 92 + common/tests/functional/testHelpCommands.js | 17 +- common/tests/functional/testOptions.js | 4 +- melodactyl/components/protocols.js | 1 - melodactyl/content/config.js | 2 - pentadactyl/NEWS | 99 +- pentadactyl/TODO | 23 +- pentadactyl/components/protocols.js | 1 - pentadactyl/config.json | 86 + pentadactyl/content/config.js | 136 +- pentadactyl/icon.png | Bin 0 -> 731 bytes pentadactyl/icon16.png | Bin 0 -> 464 bytes pentadactyl/icon64.png | Bin 0 -> 1363 bytes pentadactyl/install.rdf | 5 +- pentadactyl/locale/en-US/tutorial.xml | 127 +- teledactyl/components/protocols.js | 1 - teledactyl/config.json | 71 + teledactyl/content/compose/dactyl.xul | 98 - teledactyl/content/config.js | 71 +- teledactyl/content/mail.js | 6 +- 122 files changed, 13835 insertions(+), 7530 deletions(-) create mode 100644 .hg_archival.txt create mode 100644 .hgsub create mode 100644 .hgsubstate create mode 100644 binary/chrome.manifest create mode 100644 binary/config.mk create mode 100644 binary/install.rdf create mode 100644 binary/src/Makefile create mode 100644 binary/src/config.h create mode 100644 binary/src/dactylIUtils.idl create mode 100644 binary/src/dactylModule.cpp create mode 100644 binary/src/dactylUtils.cpp create mode 100644 binary/src/dactylUtils.h create mode 100644 binary/src/mozJSLoaderUtils.cpp create mode 100644 binary/src/mozJSLoaderUtils.h create mode 100644 binary/src/subscriptLoader.cpp delete mode 100644 common/components/protocols.js create mode 100644 common/config.json create mode 100644 common/content/key-processors.js delete mode 100644 common/javascript.vim rename common/{content/buffer.js => modules/buffer.jsm} (60%) create mode 100644 common/modules/cache.jsm create mode 100644 common/modules/dom.jsm create mode 100644 common/modules/help.jsm create mode 100644 common/modules/main.jsm create mode 100644 common/modules/protocol.jsm create mode 100644 common/skin/global-styles.css create mode 100644 common/skin/help-styles.css create mode 100644 common/tests/functional/testDOMEvents.js delete mode 120000 melodactyl/components/protocols.js delete mode 120000 pentadactyl/components/protocols.js create mode 100644 pentadactyl/config.json create mode 100644 pentadactyl/icon.png create mode 100644 pentadactyl/icon16.png create mode 100644 pentadactyl/icon64.png delete mode 120000 teledactyl/components/protocols.js create mode 100644 teledactyl/config.json delete mode 100644 teledactyl/content/compose/dactyl.xul diff --git a/.hg_archival.txt b/.hg_archival.txt new file mode 100644 index 0000000..50caf3e --- /dev/null +++ b/.hg_archival.txt @@ -0,0 +1,4 @@ +repo: 373f1649c80dea9be7b5bc9c57e8395f94f93ab1 +node: 91d4f03a135efe65e2e7de46c00ef09c78fdaae3 +branch: default +tag: pentadactyl-1.0rc1 diff --git a/.hgignore b/.hgignore index 9cb94cb..fcc3ad8 100644 --- a/.hgignore +++ b/.hgignore @@ -8,6 +8,11 @@ syntax: glob ## Generated by the build process *.xpi +*.o +*.so +*.xpt +*/.depend +*/config.local.mk */locale/*/*.html */chrome */contrib/vim/*.vba @@ -15,6 +20,10 @@ syntax: glob downloads/* .git/* +binary/src/*/*.h + +common/tests/functional/log + *.py[co] ## Editor backup and swap files diff --git a/.hgsub b/.hgsub new file mode 100644 index 0000000..2ee5d68 --- /dev/null +++ b/.hgsub @@ -0,0 +1 @@ +binary/components = https://code.google.com/p/dactyl.binary-modules/ diff --git a/.hgsubstate b/.hgsubstate new file mode 100644 index 0000000..9d9a838 --- /dev/null +++ b/.hgsubstate @@ -0,0 +1 @@ +9f8a25e7d9861892d8e6136764bb88139e0a7253 binary/components diff --git a/BREAKING_CHANGES b/BREAKING_CHANGES index 8b13789..6cd2564 100644 --- a/BREAKING_CHANGES +++ b/BREAKING_CHANGES @@ -1 +1,2 @@ - +1.0b8: + • The chrome-data: protocol has been removed. diff --git a/LICENSE.txt b/LICENSE.txt index d8fcf81..96ac8c7 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ -Copyright (c) 2006-2009 by Martin Stubenschrott - 2007-2009 by Doug Kearns - 2008-2010 by Kris Maglione +Copyright © 2006-2009 by Martin Stubenschrott +Copyright © 2007-2011 by Doug Kearns +Copyright © 2008-2011 by Kris Maglione For a full list of authors, refer the AUTHORS file. diff --git a/binary/chrome.manifest b/binary/chrome.manifest new file mode 100644 index 0000000..ff98cb0 --- /dev/null +++ b/binary/chrome.manifest @@ -0,0 +1,8 @@ + +manifest components/gecko-6.manifest appversion>=6.0 +manifest components/gecko-7.manifest appversion>=7.0 +manifest components/gecko-8.manifest platformversion>7.* +manifest components/gecko-9.manifest platformversion>8.* +manifest components/gecko-10.manifest platformversion>9.* + +# vim:se tw=0 ft=cfg: diff --git a/binary/config.mk b/binary/config.mk new file mode 100644 index 0000000..e7ae2e1 --- /dev/null +++ b/binary/config.mk @@ -0,0 +1,39 @@ + +GECKO_MAJOR ?= 10 +GECKO_MINOR ?= 0 +ABI_OS := $(shell uname -s) +ABI_ARCH := $(shell uname -m) +ABI_COMPILER := gcc3 +ABI_PLATFORM ?= $(ABI_OS)_$(ABI_ARCH)-$(ABI_COMPILER) +ABI ?= $(GECKO_MAJOR).$(GECKO_MINOR)-$(ABI_PLATFORM) +DEFINES = -DGECKO_MAJOR=$(GECKO_MAJOR) -DGECKO_MINOR=$(GECKO_MINOR) + +LIBEXT ?= so + +SED := $(shell if [ "xoo" = x$$(echo foo | sed -E 's/f(o)/\1/' 2>/dev/null) ]; \ + then echo sed -E; else echo sed -r; \ + fi) + + +PKGCONFIG ?= pkg-config +GECKO_SDK_PATH := $(shell $(PKGCONFIG) --libs libxul | $(SED) 's,([^-]|-[^L])*-L([^ ]+)/lib.*,\2,') + +CXX ?= c++ +CPP = $(CXX) -o +LINK ?= c++ + +MKDEP ?= $(CXX) -M + +PYTHON ?= python2 + +EXCPPFLAGS = -fno-rtti \ + -fno-exceptions \ + -fshort-wchar \ + -fPIC \ + -Os \ + $(NULL) + +XPIDL ?= $(PYTHON) $(GECKO_SDK_PATH)/sdk/bin +IDL_H ?= $(XPIDL)/header.py -o +IDL_XPT ?= $(XPIDL)/typelib.py -o + diff --git a/binary/install.rdf b/binary/install.rdf new file mode 100644 index 0000000..cf1f8c3 --- /dev/null +++ b/binary/install.rdf @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + diff --git a/binary/src/Makefile b/binary/src/Makefile new file mode 100644 index 0000000..02adcc4 --- /dev/null +++ b/binary/src/Makefile @@ -0,0 +1,111 @@ +ROOT = .. + +XPTDIR = $(ROOT)/components/$(ABI)/ +SODIR = $(ROOT)/components/$(ABI)/ +OBJDIR = $(ABI)/ + +MODULE = $(SODIR)dactyl + +XPIDLSRCS = \ + dactylIUtils.idl \ + $(NULL) + +CPPSRCS = \ + dactylModule.cpp \ + dactylUtils.cpp \ + mozJSLoaderUtils.cpp \ + subscriptLoader.cpp \ + $(NULL) + +HEADERS = \ + config.h \ + dactylUtils.h \ + mozJSLoaderUtils.h \ + $(XPIDLSRCS:%.idl=$(ABI)/%.h) + +GECKO_DEFINES = -DMOZILLA_STRICT_API + +GECKO_INCLUDES = -I$(ABI)/ \ + -I$(GECKO_SDK_PATH) \ + -I$(GECKO_SDK_PATH)/idl \ + -I$(GECKO_SDK_PATH)/include + +GECKO_LDFLAGS = -L$(GECKO_SDK_PATH)/bin \ + -L$(GECKO_SDK_PATH)/lib \ + -lxpcomglue_s \ + -lxpcom \ + -lnspr4 \ + -shared \ + $(NULL) + +ifeq "$(shell uname -s)" "Darwin" + GECKO_LDFLAGS += -undefined dynamic_lookup +endif + +include $(ROOT)/config.mk +sinclude $(ROOT)/config.local.mk + +CPPFLAGS += $(EXCPPFLAGS) + +XPTS = $(XPIDLSRCS:%.idl=$(XPTDIR)%.xpt) +OBJS = $(CPPSRCS:%.cpp=$(OBJDIR)%.o) +MANIFEST = $(SODIR)/components.manifest + +all: build manifest + +dirs: $(XPTDIR) $(SODIR) $(OBJDIR) + +depend: .depend + +manifest: $(MANIFEST) + +module: dirs $(MODULE).so + +dll: dirs $(MODULE).dll + +xpts: $(XPTS) + +build: dirs module xpts + +clean: + rm $(MODULE).so + + +$(OBJS): $(HEADERS) + +$(ABI)/%.h: %.idl + $(IDL_H) $@ $(GECKO_INCLUDES) $< + +$(XPTDIR)%.xpt: %.idl + $(IDL_XPT) $@ $(GECKO_INCLUDES) $< + +$(MANIFEST): Makefile + ( echo interfaces $(XPIDLSRCS:.idl=.xpt); \ + echo binary-component $(MODULE:$(SODIR)%=%).$(LIBEXT) ) \ + >$@ + + manifest=$(SODIR)/../gecko-$(GECKO_MAJOR).manifest; \ + if [ $(GECKO_MAJOR) -lt 8 ]; then part=app; else part=platform; fi; \ + line="manifest $(ABI)/components.manifest abi=$(ABI_PLATFORM) $${part}version<$(GECKO_MAJOR).*"; \ + grep >/dev/null 2>&1 "^$$line$$" $$manifest || echo $$line >>$$manifest + +_CPPFLAGS = $(CPPFLAGS) $(CXXFLAGS) $(GECKO_DEFINES) $(GECKO_INCLUDES) $(DEFINES) + +$(OBJDIR)%.o: %.cpp Makefile + $(CPP)$@ -c $(_CPPFLAGS) $< + +.depend: $(CPPSRCS) Makefile + $(MKDEP) $(_CPPFLAGS) $(CPPSRCS) | $(SED) 's;^[^ ];$(OBJDIR)&;' >.depend + +$(MODULE).so: $(OBJS) + $(LINK) -o $@ $(OBJS) $(LDFLAGS) $(GECKO_LDFLAGS) + chmod +x $@ + +$(MODULE).dll: $(OBJS) + $(LINK)$@ $(GECKO_LDFLAGS) $(OBJS) + +$(sort $(XPTDIR) $(SODIR) $(OBJDIR)): + mkdir -p $@ +.PHONY: module xpts build clean all depend manifest + +sinclude .depend diff --git a/binary/src/config.h b/binary/src/config.h new file mode 100644 index 0000000..2d46cdb --- /dev/null +++ b/binary/src/config.h @@ -0,0 +1,2 @@ +#pragma once +#include "mozilla-config.h" diff --git a/binary/src/dactylIUtils.idl b/binary/src/dactylIUtils.idl new file mode 100644 index 0000000..36adf34 --- /dev/null +++ b/binary/src/dactylIUtils.idl @@ -0,0 +1,38 @@ +/* Public Domain */ + +#include "nsISupports.idl" +#include "nsIDOMElement.idl" + +%{C++ +#include "jsapi.h" +%} + + +[scriptable, uuid(d8ef4492-8f4a-4f5d-8f19-1d71f7f895ed)] +interface dactylIUtils : nsISupports +{ + const PRUint32 DIRECTION_HORIZONTAL = 1 << 0; + const PRUint32 DIRECTION_VERTICAL = 1 << 1; + + [implicit_jscontext] + jsval createGlobal(); + + [implicit_jscontext] + jsval evalInContext(in AString source, + in jsval target, + [optional] in ACString filename, + [optional] in PRInt32 lineNumber); + + void createContents(in nsIDOMElement element); + + [implicit_jscontext] + jsval getGlobalForObject(in jsval object); + + PRUint32 getScrollable(in nsIDOMElement element); + + void loadSubScript (in wstring url + /* [optional] in jsval context, */ + /* [optional] in wstring charset */); +}; + +/* vim:se sts=4 sw=4 et ft=idl: */ diff --git a/binary/src/dactylModule.cpp b/binary/src/dactylModule.cpp new file mode 100644 index 0000000..3bc8f37 --- /dev/null +++ b/binary/src/dactylModule.cpp @@ -0,0 +1,42 @@ +#include "dactylUtils.h" + +#include "mozilla/ModuleUtils.h" + +#define NS_DACTYLUTILS_CID \ +{ 0x4d55a47c, 0x0627, 0x4339, \ + { 0x97, 0x91, 0x52, 0xef, 0x5e, 0xd4, 0xc3, 0xd1 } } + +#define NS_DACTYLUTILS_CONTRACTID \ + "@dactyl.googlecode.com/extra/utils" + +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(dactylUtils, Init) + +NS_DEFINE_NAMED_CID(NS_DACTYLUTILS_CID); + +static const mozilla::Module::CIDEntry kDactylCIDs[] = { + { &kNS_DACTYLUTILS_CID, true, NULL, dactylUtilsConstructor }, + { NULL } +}; + +static const mozilla::Module::ContractIDEntry kDactylContracts[] = { + { NS_DACTYLUTILS_CONTRACTID, &kNS_DACTYLUTILS_CID }, + { NULL } +}; + +static const mozilla::Module::CategoryEntry kDactylCategories[] = { + { NULL } +}; + +static const mozilla::Module kDactylUtilsModule = { + mozilla::Module::kVersion, + kDactylCIDs, + kDactylContracts, + kDactylCategories, + NULL, + NULL, + NULL +}; + +NSMODULE_DEFN(dactylUtilsModule) = &kDactylUtilsModule; + +/* vim:se sts=4 sw=4 et cin ft=cpp: */ diff --git a/binary/src/dactylUtils.cpp b/binary/src/dactylUtils.cpp new file mode 100644 index 0000000..23be0c1 --- /dev/null +++ b/binary/src/dactylUtils.cpp @@ -0,0 +1,381 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Contributors, possibly: + * Kris Maglione + * Jeff Walden + * Mike Shaver + * John Bandhauer + * Robert Ginda + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +#include "dactylUtils.h" + +#include "jsdbgapi.h" +// #include "jsobj.h" + +#include "nsStringAPI.h" + +#if GECKO_MAJOR < 10 + static inline JSObject* + JS_GetGlobalForScopeChain(JSContext *cx) { + JSObject *callingScope = JS_GetScopeChain(cx); + if (!callingScope) + return nsnull; + return JS_GetGlobalForObject(cx, callingScope); + } +#endif + +/* + * Evil. Evil, evil, evil. + */ +#define MOZILLA_INTERNAL_API +# define nsAString_h___ +# define nsString_h___ +# define nsStringFwd_h___ +# define nsStringGlue_h__ +# define nsContentUtils_h___ +class nsAFlatCString; +typedef nsString nsSubstring; +# include "nsIScrollableFrame.h" +#undef MOZILLA_INTERNAL_API +#include "nsPresContext.h" +#include "nsQueryFrame.h" + +#include "nsIContent.h" +#include "nsIDOMXULElement.h" +#include "nsIXULTemplateBuilder.h" +#include "nsIObserverService.h" +#include "nsIScriptSecurityManager.h" +#include "nsIXPCScriptable.h" + +#include "nsComponentManagerUtils.h" +#include "nsServiceManagerUtils.h" + + +class autoDropPrincipals { +public: + autoDropPrincipals(JSContext *context, JSPrincipals *principals) : mContext(context), mJSPrincipals(principals) {} + ~autoDropPrincipals() { + JSPRINCIPALS_DROP(mContext, mJSPrincipals); + } + +private: + JSContext *mContext; + JSPrincipals *mJSPrincipals; +}; + +static JSBool +Dump(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + if (!argc) + return JS_TRUE; + + str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]); + if (!str) + return JS_FALSE; + + size_t length; + const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length); + if (!chars) + return JS_FALSE; + + fputs(NS_ConvertUTF16toUTF8(reinterpret_cast(chars)).get(), stderr); + return JS_TRUE; +} + +static JSFunctionSpec gGlobalFun[] = { + {"dump", Dump, 1,0}, + {nsnull,nsnull,0,0} +}; + +static dactylUtils* gService = nsnull; + +dactylUtils::dactylUtils() + : mRuntime(nsnull) +{ + NS_ASSERTION(gService == nsnull, "Service already exists"); +} + +dactylUtils::~dactylUtils() +{ + mRuntimeService = nsnull; + gService = nsnull; +} + +nsresult +dactylUtils::Init() +{ + nsresult rv; + NS_ENSURE_TRUE(!gService, NS_ERROR_UNEXPECTED); + + mRuntimeService = do_GetService("@mozilla.org/js/xpc/RuntimeService;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mRuntimeService->GetRuntime(&mRuntime); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr secman = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); + NS_ENSURE_TRUE(secman, NS_ERROR_FAILURE); + + rv = secman->GetSystemPrincipal(getter_AddRefs(mSystemPrincipal)); + NS_ENSURE_TRUE(rv, rv); + NS_ENSURE_TRUE(mSystemPrincipal, NS_ERROR_FAILURE); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS1(dactylUtils, + dactylIUtils) + +NS_IMETHODIMP +dactylUtils::CreateGlobal(JSContext *cx, jsval *out) +{ + nsresult rv; + + // JS::AutoPreserveCompartment pc(cx); + + nsCOMPtr backstagePass; + rv = mRuntimeService->GetBackstagePass(getter_AddRefs(backstagePass)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr xpc = + do_GetService("@mozilla.org/js/xpc/XPConnect;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Make sure InitClassesWithNewWrappedGlobal() installs the + // backstage pass as the global in our compilation context. + JS_SetGlobalObject(cx, nsnull); + + nsCOMPtr holder; + rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass, + NS_GET_IID(nsISupports), + mSystemPrincipal, + nsnull, + nsIXPConnect:: + FLAG_SYSTEM_GLOBAL_OBJECT, + getter_AddRefs(holder)); + NS_ENSURE_SUCCESS(rv, rv); + + JSObject *global; + rv = holder->GetJSObject(&global); + NS_ENSURE_SUCCESS(rv, rv); + + JSAutoEnterCompartment ac; + NS_ENSURE_TRUE(ac.enter(cx, global), NS_ERROR_FAILURE); + + NS_ENSURE_TRUE(JS_DefineFunctions(cx, global, gGlobalFun), + NS_ERROR_FAILURE); + NS_ENSURE_TRUE(JS_DefineProfilingFunctions(cx, global), + NS_ERROR_FAILURE); + + *out = OBJECT_TO_JSVAL(global); + return NS_OK; +} + +NS_IMETHODIMP +dactylUtils::EvalInContext(const nsAString &aSource, + const jsval &aTarget, + const nsACString &aFilename, + PRInt32 aLineNumber, + JSContext *cx, + jsval *rval) +{ + nsresult rv; + + nsCOMPtr xpc(do_GetService(nsIXPConnect::GetCID(), &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCString filename; + + if (!aFilename.IsEmpty()) + filename.Assign(aFilename); + else { + nsCOMPtr frame; + xpc->GetCurrentJSStack(getter_AddRefs(frame)); + NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); + frame->GetFilename(getter_Copies(filename)); + frame->GetLineNumber(&aLineNumber); + } + + JSObject *target; + NS_ENSURE_FALSE(JSVAL_IS_PRIMITIVE(aTarget), NS_ERROR_UNEXPECTED); + target = JSVAL_TO_OBJECT(aTarget); + + + JSObject *result = target; + target = JS_FindCompilationScope(cx, target); + NS_ENSURE_TRUE(target, NS_ERROR_FAILURE); + + + nsCOMPtr secman = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); + NS_ENSURE_TRUE(secman, NS_ERROR_FAILURE); + + nsCOMPtr principal; + rv = secman->GetObjectPrincipal(cx, target, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + + JSPrincipals *jsPrincipals; + rv = principal->GetJSPrincipals(cx, &jsPrincipals); + NS_ENSURE_SUCCESS(rv, rv); + autoDropPrincipals adp(cx, jsPrincipals); + + JSObject *callingScope; + { + JSAutoRequest req(cx); + + callingScope = JS_GetGlobalForScopeChain(cx); + NS_ENSURE_TRUE(callingScope, NS_ERROR_FAILURE); + } + + { + JSAutoRequest req(cx); + JSAutoEnterCompartment ac; + jsval v; + + NS_ENSURE_TRUE(ac.enter(cx, target), NS_ERROR_FAILURE); + + JSBool ok = + JS_EvaluateUCScriptForPrincipals(cx, target, + jsPrincipals, + reinterpret_cast + (PromiseFlatString(aSource).get()), + aSource.Length(), + filename.get(), aLineNumber, &v); + + if (!ok) { + jsval exn; + if (!JS_GetPendingException(cx, &exn)) + rv = NS_ERROR_FAILURE; + else { + JS_ClearPendingException(cx); + + if (JS_WrapValue(cx, &exn)) + JS_SetPendingException(cx, exn); + } + } + else { + // Convert the result into something safe for our caller. + JSAutoRequest req(cx); + JSAutoEnterCompartment ac; + + if (!ac.enter(cx, callingScope) || !JS_WrapValue(cx, &v)) + rv = NS_ERROR_FAILURE; + + if (NS_SUCCEEDED(rv)) + *rval = v; + } + } + + return rv; +} + +NS_IMETHODIMP +dactylUtils::CreateContents(nsIDOMElement *aElement) +{ + nsCOMPtr content = do_QueryInterface(aElement); + + for (nsIContent *element = content; + element; + element = element->GetParent()) { + + nsCOMPtr xulelem = do_QueryInterface(element); + if (xulelem) { + nsCOMPtr builder; + xulelem->GetBuilder(getter_AddRefs(builder)); + if (builder) { + builder->CreateContents(content, PR_TRUE); + break; + } + } + } + return NS_OK; +} + +namespace XPCWrapper { + extern JSObject *UnsafeUnwrapSecurityWrapper(JSObject *obj); +}; + +NS_IMETHODIMP +dactylUtils::GetGlobalForObject(const jsval &aObject, + JSContext *cx, + jsval *rval) +{ + nsresult rv; + + NS_ENSURE_FALSE(JSVAL_IS_PRIMITIVE(aObject), + NS_ERROR_XPC_BAD_CONVERT_JS); + + JSObject *obj = XPCWrapper::UnsafeUnwrapSecurityWrapper(JSVAL_TO_OBJECT(aObject)); + + JSObject *global = JS_GetGlobalForObject(cx, obj); + *rval = OBJECT_TO_JSVAL(global); + + /* + // Outerize if necessary. + if (JSObjectOp outerize = global->getClass()->ext.outerObject) + *rval = OBJECT_TO_JSVAL(outerize(cx, global)); + */ + + return NS_OK; +} + +NS_IMETHODIMP +dactylUtils::GetScrollable(nsIDOMElement *aElement, PRUint32 *rval) +{ + nsCOMPtr content = do_QueryInterface(aElement); + + nsIFrame *frame = content->GetPrimaryFrame(); + nsIScrollableFrame *scrollFrame = do_QueryFrame(frame); + + *rval = 0; + if (scrollFrame) { + nsPresContext::ScrollbarStyles ss = scrollFrame->GetScrollbarStyles(); + PRUint32 scrollbarVisibility = scrollFrame->GetScrollbarVisibility(); + nsRect scrollRange = scrollFrame->GetScrollRange(); + + if (ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN && + ((scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) || + scrollRange.width > 0)) + *rval |= dactylIUtils::DIRECTION_HORIZONTAL; + + if (ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN && + ((scrollbarVisibility & nsIScrollableFrame::VERTICAL) || + scrollRange.height > 0)) + *rval |= dactylIUtils::DIRECTION_VERTICAL; + } + + return NS_OK; +} + +/* vim:se sts=4 sw=4 et cin ft=cpp: */ diff --git a/binary/src/dactylUtils.h b/binary/src/dactylUtils.h new file mode 100644 index 0000000..7454536 --- /dev/null +++ b/binary/src/dactylUtils.h @@ -0,0 +1,36 @@ + +#pragma once + +#include "config.h" +#include "dactylIUtils.h" + +#include "nsISupports.h" +#include "nsIPrincipal.h" +#include "nsIXPConnect.h" + +#include "jsapi.h" +#include "jsfriendapi.h" +#include "nsIJSRuntimeService.h" +#include "nsIJSContextStack.h" + +#include "nsCOMPtr.h" + +class dactylUtils : public dactylIUtils { +public: + dactylUtils() NS_HIDDEN; + ~dactylUtils() NS_HIDDEN; + + NS_DECL_ISUPPORTS + NS_DECL_DACTYLIUTILS + + NS_HIDDEN_(nsresult) Init(); + +private: + + nsCOMPtr mRuntimeService; + JSRuntime *mRuntime; + + nsCOMPtr mSystemPrincipal; +}; + +/* vim:se sts=4 sw=4 et cin ft=cpp: */ diff --git a/binary/src/mozJSLoaderUtils.cpp b/binary/src/mozJSLoaderUtils.cpp new file mode 100644 index 0000000..94b371b --- /dev/null +++ b/binary/src/mozJSLoaderUtils.cpp @@ -0,0 +1,196 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010-2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Michael Wu + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "mozJSLoaderUtils.h" +#include "nsAutoPtr.h" + +#include "jsapi.h" +#include "jsxdrapi.h" + +#include "mozilla/scache/StartupCache.h" +#include "mozilla/scache/StartupCacheUtils.h" + +#include "nsIChromeRegistry.h" +#include "nsIIOService.h" +#include "nsIResProtocolHandler.h" +#include "nsNetUtil.h" + +using namespace mozilla::scache; + +static nsresult +ReadScriptFromStream(JSContext *cx, nsIObjectInputStream *stream, + JSScriptType **script) +{ + *script = nsnull; + + PRUint32 size; + nsresult rv = stream->Read32(&size); + NS_ENSURE_SUCCESS(rv, rv); + + char *data; + rv = stream->ReadBytes(size, &data); + NS_ENSURE_SUCCESS(rv, rv); + + JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_DECODE); + NS_ENSURE_TRUE(xdr, NS_ERROR_OUT_OF_MEMORY); + + xdr->userdata = stream; + JS_XDRMemSetData(xdr, data, size); + + if (!JS_XDRScript(xdr, script)) { + rv = NS_ERROR_FAILURE; + } + + // Update data in case ::JS_XDRScript called back into C++ code to + // read an XPCOM object. + // + // In that case, the serialization process must have flushed a run + // of counted bytes containing JS data at the point where the XPCOM + // object starts, after which an encoding C++ callback from the JS + // XDR code must have written the XPCOM object directly into the + // nsIObjectOutputStream. + // + // The deserialization process will XDR-decode counted bytes up to + // but not including the XPCOM object, then call back into C++ to + // read the object, then read more counted bytes and hand them off + // to the JSXDRState, so more JS data can be decoded. + // + // This interleaving of JS XDR data and XPCOM object data may occur + // several times beneath the call to ::JS_XDRScript, above. At the + // end of the day, we need to free (via nsMemory) the data owned by + // the JSXDRState. So we steal it back, nulling xdr's buffer so it + // doesn't get passed to ::JS_free by ::JS_XDRDestroy. + + uint32 length; + data = static_cast(JS_XDRMemGetData(xdr, &length)); + JS_XDRMemSetData(xdr, nsnull, 0); + JS_XDRDestroy(xdr); + + // If data is null now, it must have been freed while deserializing an + // XPCOM object (e.g., a principal) beneath ::JS_XDRScript. + nsMemory::Free(data); + + return rv; +} + +static nsresult +WriteScriptToStream(JSContext *cx, JSScriptType *script, + nsIObjectOutputStream *stream) +{ + JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_ENCODE); + NS_ENSURE_TRUE(xdr, NS_ERROR_OUT_OF_MEMORY); + + xdr->userdata = stream; + nsresult rv = NS_OK; + + if (JS_XDRScript(xdr, &script)) { + // Get the encoded JSXDRState data and write it. The JSXDRState owns + // this buffer memory and will free it beneath ::JS_XDRDestroy. + // + // If an XPCOM object needs to be written in the midst of the JS XDR + // encoding process, the C++ code called back from the JS engine (e.g., + // nsEncodeJSPrincipals in caps/src/nsJSPrincipals.cpp) will flush data + // from the JSXDRState to aStream, then write the object, then return + // to JS XDR code with xdr reset so new JS data is encoded at the front + // of the xdr's data buffer. + // + // However many XPCOM objects are interleaved with JS XDR data in the + // stream, when control returns here from ::JS_XDRScript, we'll have + // one last buffer of data to write to aStream. + + uint32 size; + const char* data = reinterpret_cast + (JS_XDRMemGetData(xdr, &size)); + NS_ASSERTION(data, "no decoded JSXDRState data!"); + + rv = stream->Write32(size); + if (NS_SUCCEEDED(rv)) { + rv = stream->WriteBytes(data, size); + } + } else { + rv = NS_ERROR_FAILURE; // likely to be a principals serialization error + } + + JS_XDRDestroy(xdr); + return rv; +} + +nsresult +ReadCachedScript(nsIStartupCache* cache, nsACString &uri, JSContext *cx, JSScriptType **script) +{ + nsresult rv; + + nsAutoArrayPtr buf; + PRUint32 len; + rv = cache->GetBuffer(PromiseFlatCString(uri).get(), getter_Transfers(buf), + &len); + if (NS_FAILED(rv)) { + return rv; // don't warn since NOT_AVAILABLE is an ok error + } + + nsCOMPtr ois; + rv = NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(ois)); + NS_ENSURE_SUCCESS(rv, rv); + buf.forget(); + + return ReadScriptFromStream(cx, ois, script); +} + +nsresult +WriteCachedScript(nsIStartupCache* cache, nsACString &uri, JSContext *cx, JSScriptType *script) +{ + nsresult rv; + + nsCOMPtr oos; + nsCOMPtr storageStream; + rv = NewObjectOutputWrappedStorageStream(getter_AddRefs(oos), + getter_AddRefs(storageStream), + true); + NS_ENSURE_SUCCESS(rv, rv); + + rv = WriteScriptToStream(cx, script, oos); + oos->Close(); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoArrayPtr buf; + PRUint32 len; + rv = NewBufferFromStorageStream(storageStream, getter_Transfers(buf), &len); + NS_ENSURE_SUCCESS(rv, rv); + + rv = cache->PutBuffer(PromiseFlatCString(uri).get(), buf, len); + return rv; +} diff --git a/binary/src/mozJSLoaderUtils.h b/binary/src/mozJSLoaderUtils.h new file mode 100644 index 0000000..372fdb2 --- /dev/null +++ b/binary/src/mozJSLoaderUtils.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Michael Wu + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef mozJSLoaderUtils_h +#define mozJSLoaderUtils_h + +#include "config.h" + +/* + * This is evil. Very evil. +#define nsString_h___ +#include "nsStringGlue.h" + */ + +#include "nsIStartupCache.h" +#include "nsStringAPI.h" +#include "jsapi.h" + +#if defined(GECKO_MAJOR) && GECKO_MAJOR < 9 +#include "jsapi.h" +# define JS_XDRScript JS_XDRScriptObject + typedef JSObject JSScriptType; + +# if GECKO_MAJOR < 8 +# define NewObjectInputStreamFromBuffer NS_NewObjectInputStreamFromBuffer +# define NewBufferFromStorageStream NS_NewBufferFromStorageStream +# if GECKO_MAJOR > 6 +# define NewObjectOutputWrappedStorageStream NS_NewObjectOutputWrappedStorageStream +# else +# define NewObjectOutputWrappedStorageStream(a, b, c) NS_NewObjectOutputWrappedStorageStream((a), (b)) +# endif +# endif +#else + typedef JSScript JSScriptType; +#endif + +class nsIURI; + +namespace mozilla { +namespace scache { +class StartupCache; +} +} + +nsresult +ReadCachedScript(nsIStartupCache* cache, nsACString &uri, + JSContext *cx, JSScriptType **scriptObj); + +nsresult +WriteCachedScript(nsIStartupCache* cache, nsACString &uri, + JSContext *cx, JSScriptType *scriptObj); +#endif /* mozJSLoaderUtils_h */ diff --git a/binary/src/subscriptLoader.cpp b/binary/src/subscriptLoader.cpp new file mode 100644 index 0000000..1c7b5cc --- /dev/null +++ b/binary/src/subscriptLoader.cpp @@ -0,0 +1,583 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert Ginda + * Kris Maglione + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * What follows is the ordinary mozIJSSubScriptLoader modified only to strip the + * useless, irritating, and troublesome "foo -> " prefixes from filenames. + */ + +#include "dactylUtils.h" +#include "mozJSLoaderUtils.h" + +#include "nsIServiceManager.h" +#include "nsIXPConnect.h" + +#include "nsIURI.h" +#include "nsIIOService.h" +#include "nsIChannel.h" +#include "nsIConsoleService.h" +#include "nsIScriptError.h" +#include "nsIInputStream.h" +#include "nsNetCID.h" +#include "nsAutoPtr.h" +#include "nsNetUtil.h" +#include "nsIProtocolHandler.h" +#include "nsIScriptSecurityManager.h" +#include "nsIFileURL.h" + +// ConvertToUTF16 +#include "nsICharsetConverterManager.h" +#include "nsIUnicodeDecoder.h" +template +inline PRBool EnsureStringLength(T& aStr, PRUint32 aLen) +{ + aStr.SetLength(aLen); + return (aStr.Length() == aLen); +} + +#include "jsapi.h" +#include "jscntxt.h" +#include "jsdbgapi.h" +#include "jsfriendapi.h" + +#if GECKO_MAJOR < 10 + static inline JSVersion + JS_GetVersion(JSContext *cx) { + return cx->findVersion(); + } +#endif + +#include "mozilla/FunctionTimer.h" +#include "mozilla/scache/StartupCache.h" +#include "mozilla/scache/StartupCacheUtils.h" + +using namespace mozilla::scache; +class nsACString_internal : nsACString {}; + +namespace mozilla { + namespace scache { + nsresult PathifyURI(nsIURI *in, nsACString_internal &out); + } +} + +/* load() error msgs, XXX localize? */ +#define LOAD_ERROR_NOSERVICE "Error creating IO Service." +#define LOAD_ERROR_NOURI "Error creating URI (invalid URL scheme?)" +#define LOAD_ERROR_NOSCHEME "Failed to get URI scheme. This is bad." +#define LOAD_ERROR_URI_NOT_LOCAL "Trying to load a non-local URI." +#define LOAD_ERROR_NOSTREAM "Error opening input stream (invalid filename?)" +#define LOAD_ERROR_NOCONTENT "ContentLength not available (not a local URL?)" +#define LOAD_ERROR_BADCHARSET "Error converting to specified charset" +#define LOAD_ERROR_BADREAD "File Read Error." +#define LOAD_ERROR_READUNDERFLOW "File Read Error (underflow.)" +#define LOAD_ERROR_NOPRINCIPALS "Failed to get principals." +#define LOAD_ERROR_NOSPEC "Failed to get URI spec. This is bad." + +/* Internal linkage, bloody hell... */ +static nsresult +ConvertToUTF16(nsIChannel* aChannel, const PRUint8* aData, + PRUint32 aLength, const nsString& aHintCharset, + nsString& aString) +{ + if (!aLength) { + aString.Truncate(); + return NS_OK; + } + + nsCAutoString characterSet; + + nsresult rv = NS_OK; + if (aChannel) { + rv = aChannel->GetContentCharset(characterSet); + } + + if (!aHintCharset.IsEmpty() && (NS_FAILED(rv) || characterSet.IsEmpty())) { + // charset name is always ASCII. + LossyCopyUTF16toASCII(aHintCharset, characterSet); + } + + if (characterSet.IsEmpty()) { + // fall back to ISO-8859-1, see bug 118404 + characterSet.AssignLiteral("ISO-8859-1"); + } + + nsCOMPtr charsetConv = + do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); + + nsCOMPtr unicodeDecoder; + + if (NS_SUCCEEDED(rv) && charsetConv) { + rv = charsetConv->GetUnicodeDecoder(characterSet.get(), + getter_AddRefs(unicodeDecoder)); + if (NS_FAILED(rv)) { + // fall back to ISO-8859-1 if charset is not supported. (bug 230104) + rv = charsetConv->GetUnicodeDecoderRaw("ISO-8859-1", + getter_AddRefs(unicodeDecoder)); + } + } + + // converts from the charset to unicode + if (NS_SUCCEEDED(rv)) { + PRInt32 unicodeLength = 0; + + rv = unicodeDecoder->GetMaxLength(reinterpret_cast(aData), + aLength, &unicodeLength); + if (NS_SUCCEEDED(rv)) { + if (!EnsureStringLength(aString, unicodeLength)) + return NS_ERROR_OUT_OF_MEMORY; + + PRUnichar *ustr = aString.BeginWriting(); + + PRInt32 consumedLength = 0; + PRInt32 originalLength = aLength; + PRInt32 convertedLength = 0; + PRInt32 bufferLength = unicodeLength; + do { + rv = unicodeDecoder->Convert(reinterpret_cast(aData), + (PRInt32 *) &aLength, ustr, + &unicodeLength); + if (NS_FAILED(rv)) { + // if we failed, we consume one byte, replace it with U+FFFD + // and try the conversion again. + ustr[unicodeLength++] = (PRUnichar)0xFFFD; + ustr += unicodeLength; + + unicodeDecoder->Reset(); + } + aData += ++aLength; + consumedLength += aLength; + aLength = originalLength - consumedLength; + convertedLength += unicodeLength; + unicodeLength = bufferLength - convertedLength; + } while (NS_FAILED(rv) && (originalLength > consumedLength) && (bufferLength > convertedLength)); + aString.SetLength(convertedLength); + } + } + return rv; +} + +// We just use the same reporter as the component loader +static void +mozJSLoaderErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep) +{ + nsresult rv; + + /* Use the console service to register the error. */ + nsCOMPtr consoleService = + do_GetService(NS_CONSOLESERVICE_CONTRACTID); + + /* + * Make an nsIScriptError, populate it with information from this + * error, then log it with the console service. The UI can then + * poll the service to update the Error console. + */ + nsCOMPtr errorObject = + do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); + + if (consoleService && errorObject) { + /* + * Got an error object; prepare appropriate-width versions of + * various arguments to it. + */ + nsAutoString fileUni; + fileUni.Assign(NS_ConvertUTF8toUTF16(rep->filename)); + + PRUint32 column = rep->uctokenptr - rep->uclinebuf; + + rv = errorObject->Init(reinterpret_cast + (rep->ucmessage), + fileUni.get(), + reinterpret_cast + (rep->uclinebuf), + rep->lineno, column, rep->flags, + "component javascript"); + if (NS_SUCCEEDED(rv)) { + rv = consoleService->LogMessage(errorObject); + if (NS_SUCCEEDED(rv)) { + // We're done! Skip return to fall thru to stderr + // printout, for the benefit of those invoking the + // browser with -console + // return; + } + } + } + + /* + * If any of the above fails for some reason, fall back to + * printing to stderr. + */ +} + +static JSBool +Dump(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + if (!argc) + return JS_TRUE; + + str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]); + if (!str) + return JS_FALSE; + + size_t length; + const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length); + if (!chars) + return JS_FALSE; + + fputs(NS_ConvertUTF16toUTF8(reinterpret_cast(chars)).get(), stderr); + return JS_TRUE; +} + +static nsresult +ReportError(JSContext *cx, const char *msg) +{ + JS_SetPendingException(cx, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, msg))); + return NS_OK; +} + +static nsresult +ReadScript(nsIURI *uri, JSContext *cx, JSObject *target_obj, + jschar *charset, const char *uriStr, + nsIIOService *serv, nsIPrincipal *principal, + JSScriptType **scriptObjp) +{ + nsCOMPtr chan; + nsCOMPtr instream; + JSPrincipals *jsPrincipals; + JSErrorReporter er; + + nsresult rv; + // Instead of calling NS_OpenURI, we create the channel ourselves and call + // SetContentType, to avoid expensive MIME type lookups (bug 632490). + rv = NS_NewChannel(getter_AddRefs(chan), uri, serv, + nsnull, nsnull, nsIRequest::LOAD_NORMAL); + if (NS_SUCCEEDED(rv)) { + chan->SetContentType(NS_LITERAL_CSTRING("application/javascript")); + rv = chan->Open(getter_AddRefs(instream)); + } + + if (NS_FAILED(rv)) { + return ReportError(cx, LOAD_ERROR_NOSTREAM); + } + + PRInt32 len = -1; + + rv = chan->GetContentLength(&len); + if (NS_FAILED(rv) || len == -1) { + return ReportError(cx, LOAD_ERROR_NOCONTENT); + } + + nsCString buf; + rv = NS_ReadInputStreamToString(instream, buf, len); + if (NS_FAILED(rv)) + return rv; + + /* we can't hold onto jsPrincipals as a module var because the + * JSPRINCIPALS_DROP macro takes a JSContext, which we won't have in the + * destructor */ + rv = principal->GetJSPrincipals(cx, &jsPrincipals); + if (NS_FAILED(rv) || !jsPrincipals) { + return ReportError(cx, LOAD_ERROR_NOPRINCIPALS); + } + + /* set our own error reporter so we can report any bad things as catchable + * exceptions, including the source/line number */ + er = JS_SetErrorReporter(cx, mozJSLoaderErrorReporter); + + if (charset) { + nsString script; + rv = ConvertToUTF16( + nsnull, reinterpret_cast(buf.get()), len, + nsDependentString(reinterpret_cast(charset)), script); + + if (NS_FAILED(rv)) { + JSPRINCIPALS_DROP(cx, jsPrincipals); + return ReportError(cx, LOAD_ERROR_BADCHARSET); + } + + *scriptObjp = + JS_CompileUCScriptForPrincipals(cx, target_obj, jsPrincipals, + reinterpret_cast(script.get()), + script.Length(), uriStr, 1); + } else { + *scriptObjp = + JS_CompileScriptForPrincipals(cx, target_obj, jsPrincipals, buf.get(), + len, uriStr, 1); + } + + JSPRINCIPALS_DROP(cx, jsPrincipals); + + /* repent for our evil deeds */ + JS_SetErrorReporter(cx, er); + + return NS_OK; +} + +NS_IMETHODIMP /* args and return value are delt with using XPConnect and JSAPI */ +dactylUtils::LoadSubScript (const PRUnichar * aURL + /* [, JSObject *target_obj] */) +{ + /* + * Loads a local url and evals it into the current cx + * Synchronous (an async version would be cool too.) + * url: The url to load. Must be local so that it can be loaded + * synchronously. + * target_obj: Optional object to eval the script onto (defaults to context + * global) + * returns: Whatever jsval the script pointed to by the url returns. + * Should ONLY (O N L Y !) be called from JavaScript code. + */ + + /* gotta define most of this stuff up here because of all the gotos, + * defined the rest up here to be consistent */ + nsresult rv; + JSBool ok; + +#ifdef NS_FUNCTION_TIMER + NS_TIME_FUNCTION_FMT("%s (line %d) (url: %s)", MOZ_FUNCTION_NAME, + __LINE__, NS_LossyConvertUTF16toASCII(aURL).get()); +#else + (void)aURL; // prevent compiler warning +#endif + + /* get JS things from the CallContext */ + nsCOMPtr xpc = do_GetService(nsIXPConnect::GetCID()); + if (!xpc) return NS_ERROR_FAILURE; + + nsAXPCNativeCallContext *cc = nsnull; + rv = xpc->GetCurrentNativeCallContext(&cc); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + JSContext *cx; + rv = cc->GetJSContext (&cx); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + PRUint32 argc; + rv = cc->GetArgc (&argc); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + jsval *argv; + rv = cc->GetArgvPtr (&argv); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + jsval *rval; + rv = cc->GetRetValPtr (&rval); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + /* set mJSPrincipals if it's not here already */ + if (!mSystemPrincipal) + { + nsCOMPtr secman = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); + if (!secman) + return rv; + + rv = secman->GetSystemPrincipal(getter_AddRefs(mSystemPrincipal)); + if (NS_FAILED(rv) || !mSystemPrincipal) + return rv; + } + + JSAutoRequest ar(cx); + + JSString *url; + JSObject *target_obj = nsnull; + jschar *charset = nsnull; + ok = JS_ConvertArguments (cx, argc, argv, "S / o W", &url, &target_obj, &charset); + if (!ok) + { + /* let the exception raised by JS_ConvertArguments show through */ + return NS_OK; + } + + JSAutoByteString urlbytes(cx, url); + if (!urlbytes) + { + return NS_OK; + } + + if (!target_obj) + { + /* if the user didn't provide an object to eval onto, find the global + * object by walking the parent chain of the calling object */ + + nsCOMPtr wn; + rv = cc->GetCalleeWrapper (getter_AddRefs(wn)); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + rv = wn->GetJSObject (&target_obj); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + JSObject *maybe_glob = JS_GetParent (cx, target_obj); + while (maybe_glob != nsnull) + { + target_obj = maybe_glob; + maybe_glob = JS_GetParent (cx, maybe_glob); + } + } + + // Remember an object out of the calling compartment so that we + // can properly wrap the result later. + nsCOMPtr principal = mSystemPrincipal; + JSObject *result_obj = target_obj; + target_obj = JS_FindCompilationScope(cx, target_obj); + if (!target_obj) + return NS_ERROR_FAILURE; + + if (target_obj != result_obj) + { + nsCOMPtr secman = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); + if (!secman) + return NS_ERROR_FAILURE; + + rv = secman->GetObjectPrincipal(cx, target_obj, getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + } + + JSAutoEnterCompartment ac; + if (!ac.enter(cx, target_obj)) + return NS_ERROR_UNEXPECTED; + + /* load up the url. From here on, failures are reflected as ``custom'' + * js exceptions */ + nsCOMPtr uri; + nsCAutoString uriStr; + nsCAutoString scheme; + + JSStackFrame* frame = nsnull; + JSScript* script = nsnull; + + // Figure out who's calling us + do + { + frame = JS_FrameIterator(cx, &frame); + + if (frame) + script = JS_GetFrameScript(cx, frame); + } while (frame && !script); + + if (!script) + { + // No script means we don't know who's calling, bail. + + return NS_ERROR_FAILURE; + } + + nsCOMPtr serv = do_GetService(NS_IOSERVICE_CONTRACTID); + if (!serv) { + return ReportError(cx, LOAD_ERROR_NOSERVICE); + } + + // Make sure to explicitly create the URI, since we'll need the + // canonicalized spec. + rv = NS_NewURI(getter_AddRefs(uri), urlbytes.ptr(), nsnull, serv); + if (NS_FAILED(rv)) { + return ReportError(cx, LOAD_ERROR_NOURI); + } + + rv = uri->GetSpec(uriStr); + if (NS_FAILED(rv)) { + return ReportError(cx, LOAD_ERROR_NOSPEC); + } + + rv = uri->GetScheme(scheme); + if (NS_FAILED(rv)) { + return ReportError(cx, LOAD_ERROR_NOSCHEME); + } + + bool writeScript = false; + JSScriptType *scriptObj = nsnull; + JSVersion version = JS_GetVersion(cx); + + nsCAutoString cachePath; + cachePath.Append("jssubloader/"); + cachePath.AppendInt(version); + if (charset) { + cachePath.Append("/"); + cachePath.Append(NS_ConvertUTF16toUTF8( + nsDependentString(reinterpret_cast(charset)))); + } + + if (false) + // This is evil. Very evil. Unfortunately, the PathifyURI symbol is + // exported, but with an argument type that we don't have access to. + PathifyURI(uri, *(nsACString_internal*)&cachePath); + else { + cachePath.Append("/"); + cachePath.Append(uriStr); + } + + // Suppress caching if we're compiling as content. + nsCOMPtr cache; + if (mSystemPrincipal) { + cache = do_GetService("@mozilla.org/startupcache/cache;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = ReadCachedScript(cache, cachePath, cx, &scriptObj); + } + + if (!scriptObj) { + rv = ReadScript(uri, cx, target_obj, charset, (char *)uriStr.get(), serv, + principal, &scriptObj); + writeScript = true; + } + + if (NS_FAILED(rv) || !scriptObj) + return rv; + + ok = false; + if (scriptObj) + ok = JS_ExecuteScriptVersion(cx, target_obj, scriptObj, rval, version); + + if (ok) { + JSAutoEnterCompartment rac; + if (!rac.enter(cx, result_obj) || !JS_WrapValue(cx, rval)) + return NS_ERROR_UNEXPECTED; + } + + if (cache && ok && writeScript) { + WriteCachedScript(cache, cachePath, cx, scriptObj); + } + + cc->SetReturnValueWasSet (ok); + return NS_OK; +} + diff --git a/common/Makefile b/common/Makefile index b9e8022..ef118e8 100644 --- a/common/Makefile +++ b/common/Makefile @@ -32,15 +32,16 @@ MAKE_JAR = sh $(BASE)/make_jar.sh # TODO: specify source files manually? JAR_BASES = $(TOP) $(BASE) +JAR_FILES = config.json JAR_DIRS = content skin locale modules -JAR_TEXTS = js jsm css dtd xml xul html xhtml xsl properties +JAR_TEXTS = js jsm css dtd xml xul html xhtml xsl properties json JAR_BINS = png CHROME = $(MANGLE)/ JAR = $(CHROME)$(NAME).jar XPI_BASES = $(JAR_BASES) $(TOP)/.. -XPI_FILES = bootstrap.js TODO AUTHORS Donors NEWS LICENSE.txt +XPI_FILES = icon.png icon64.png bootstrap.js TODO AUTHORS Donors NEWS LICENSE.txt XPI_DIRS = components $(MANGLE) defaults XPI_TEXTS = js jsm $(JAR_TEXTS) XPI_BINS = $(JAR_BINS) @@ -142,14 +143,20 @@ install: exit 1; \ fi; \ \ - ext="$$profile/extensions/$(UUID)"; \ - mkdir -p "$$(dirname "$$ext")"; \ - rm -rf "$$ext.xpi" "$$ext"; \ - echo "Installing to $$ext"; \ - if which cygpath >/dev/null 2>&1; \ - then cygpath -wa .; \ - else pwd; \ - fi >"$$ext" + install() { \ + ext="$$profile/extensions/$$2"; \ + mkdir -p "$$(dirname "$$ext")"; \ + rm -rf "$$ext.xpi" "$$ext"; \ + \ + echo "Installing $$2 to $$ext"; \ + if which cygpath >/dev/null 2>&1; \ + then cygpath -wa $$1; \ + else (cd $$1; pwd); \ + fi >"$$ext"; \ + }; \ + install . $(UUID); \ + install ../binary binary@dactyl.googlecode.com; \ + installxpi: xpi $(HOSTAPP) $(XPI) diff --git a/common/bootstrap.js b/common/bootstrap.js index ccf1007..e029387 100755 --- a/common/bootstrap.js +++ b/common/bootstrap.js @@ -9,10 +9,7 @@ const NAME = "bootstrap"; const global = this; -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; -const Cr = Components.results; +var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; function module(uri) { let obj = {}; @@ -29,24 +26,20 @@ const resourceProto = Services.io.getProtocolHandler("resource") const categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager); const manager = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); -const BOOTSTRAP_JSM = "resource://dactyl/bootstrap.jsm"; - +const DISABLE_ACR = "resource://dactyl-content/disable-acr.jsm"; +const BOOTSTRAP_JSM = "resource://dactyl/bootstrap.jsm"; const BOOTSTRAP_CONTRACT = "@dactyl.googlecode.com/base/bootstrap"; -JSMLoader = JSMLoader || BOOTSTRAP_CONTRACT in Cc && Cc[BOOTSTRAP_CONTRACT].getService().wrappedJSObject.loader; - -var JSMLoader = BOOTSTRAP_CONTRACT in Components.classes && - Components.classes[BOOTSTRAP_CONTRACT].getService().wrappedJSObject.loader; -// Temporary migration code. -if (!JSMLoader && "@mozilla.org/fuel/application;1" in Components.classes) - JSMLoader = Components.classes["@mozilla.org/fuel/application;1"] - .getService(Components.interfaces.extIApplication) - .storage.get("dactyl.JSMLoader", null); +var JSMLoader = BOOTSTRAP_CONTRACT in Cc && Cc[BOOTSTRAP_CONTRACT].getService().wrappedJSObject.loader; +var name = "dactyl"; function reportError(e) { - dump("\ndactyl: bootstrap: " + e + "\n" + (e.stack || Error().stack) + "\n"); + dump("\n" + name + ": bootstrap: " + e + "\n" + (e.stack || Error().stack) + "\n"); Cu.reportError(e); } +function debug(msg) { + dump(name + ": " + msg + "\n"); +} function httpGet(url) { let xmlhttp = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); @@ -65,6 +58,16 @@ let components = {}; let resources = []; let getURI = null; +function updateLoader() { + try { + JSMLoader.loader = Cc["@dactyl.googlecode.com/extra/utils"].getService(Ci.dactylIUtils); + } + catch (e) {}; +} + +/** + * Performs necessary migrations after a version change. + */ function updateVersion() { try { function isDev(ver) /^hg|pre$/.test(ver); @@ -77,6 +80,11 @@ function updateVersion() { localPrefs.set("lastVersion", addon.version); + // We're switching from a nightly version to a stable or + // semi-stable version or vice versa. + // + // Disable automatic updates when switching to nightlies, + // restore the default action when switching to stable. if (!config.lastVersion || isDev(config.lastVersion) != isDev(addon.version)) addon.applyBackgroundUpdates = AddonManager[isDev(addon.version) ? "AUTOUPDATE_DISABLE" : "AUTOUPDATE_DEFAULT"]; } @@ -86,19 +94,24 @@ function updateVersion() { } function startup(data, reason) { - dump("dactyl: bootstrap: startup " + reasonToString(reason) + "\n"); + debug("bootstrap: startup " + reasonToString(reason)); basePath = data.installPath; if (!initialized) { initialized = true; - dump("dactyl: bootstrap: init" + " " + data.id + "\n"); + debug("bootstrap: init" + " " + data.id); addonData = data; addon = data; + name = data.id.replace(/@.*/, ""); AddonManager.getAddonByID(addon.id, function (a) { addon = a; + + updateLoader(); updateVersion(); + if (typeof require !== "undefined") + require(global, "main"); }); if (basePath.isDirectory()) @@ -109,7 +122,8 @@ function startup(data, reason) { }; else getURI = function getURI(path) - Services.io.newURI("jar:" + Services.io.newFileURI(basePath).spec + "!/" + path, null, null); + Services.io.newURI("jar:" + Services.io.newFileURI(basePath).spec.replace(/!/g, "%21") + "!" + + "/" + path, null, null); try { init(); @@ -120,6 +134,14 @@ function startup(data, reason) { } } +/** + * An XPCOM class factory proxy. Loads the JavaScript module at *url* + * when an instance is to be created and calls its NSGetFactory method + * to obtain the actual factory. + * + * @param {string} url The URL of the module housing the real factory. + * @param {string} classID The CID of the class this factory represents. + */ function FactoryProxy(url, classID) { this.url = url; this.classID = Components.ID(classID); @@ -127,12 +149,12 @@ function FactoryProxy(url, classID) { FactoryProxy.prototype = { QueryInterface: XPCOMUtils.generateQI(Ci.nsIFactory), register: function () { - dump("dactyl: bootstrap: register: " + this.classID + " " + this.contractID + "\n"); + debug("bootstrap: register: " + this.classID + " " + this.contractID); JSMLoader.registerFactory(this); }, get module() { - dump("dactyl: bootstrap: create module: " + this.contractID + "\n"); + debug("bootstrap: create module: " + this.contractID); Object.defineProperty(this, "module", { value: {}, enumerable: true }); JSMLoader.load(this.url, this.module); @@ -145,7 +167,7 @@ FactoryProxy.prototype = { } function init() { - dump("dactyl: bootstrap: init\n"); + debug("bootstrap: init"); let manifestURI = getURI("chrome.manifest"); let manifest = httpGet(manifestURI.spec) @@ -185,50 +207,60 @@ function init() { let pref = "extensions.dactyl.cacheFlushCheck"; let val = addon.version + "-" + hardSuffix; if (!Services.prefs.prefHasUserValue(pref) || Services.prefs.getCharPref(pref) != val) { + var cacheFlush = true; Services.obs.notifyObservers(null, "startupcache-invalidate", ""); Services.prefs.setCharPref(pref, val); } try { - module("resource://dactyl-content/disable-acr.jsm").init(addon.id); + module(DISABLE_ACR).init(addon.id); } catch (e) { reportError(e); } if (JSMLoader) { + // Temporary hacks until platforms and dactyl releases that don't + // support Cu.unload are phased out. if (Cu.unload) { + // Upgrading from dactyl release without Cu.unload support. Cu.unload(BOOTSTRAP_JSM); for (let [name] in Iterator(JSMLoader.globals)) Cu.unload(~name.indexOf(":") ? name : "resource://dactyl" + JSMLoader.suffix + "/" + name); } - else if (JSMLoader.bump != 5) // Temporary hack + else if (JSMLoader.bump != 6) { + // We're in a version without Cu.unload support and the + // JSMLoader interface has changed. Bump off the old one. Services.scriptloader.loadSubScript("resource://dactyl" + suffix + "/bootstrap.jsm", Cu.import(BOOTSTRAP_JSM, global)); + } } - if (!JSMLoader || JSMLoader.bump !== 5 || Cu.unload) + if (!JSMLoader || JSMLoader.bump !== 6 || Cu.unload) Cu.import(BOOTSTRAP_JSM, global); + JSMLoader.name = name; JSMLoader.bootstrap = this; JSMLoader.load(BOOTSTRAP_JSM, global); JSMLoader.init(suffix); + JSMLoader.cacheFlush = cacheFlush; JSMLoader.load("base.jsm", global); - if (!(BOOTSTRAP_CONTRACT in Cc)) - manager.registerFactory(Components.ID("{f541c8b0-fe26-4621-a30b-e77d21721fb5}"), - String("{f541c8b0-fe26-4621-a30b-e77d21721fb5}"), - BOOTSTRAP_CONTRACT, { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]), - instance: { - QueryInterface: XPCOMUtils.generateQI([]), - contractID: BOOTSTRAP_CONTRACT, - wrappedJSObject: {} - }, - createInstance: function () this.instance - }); + if (!(BOOTSTRAP_CONTRACT in Cc)) { + // Use Sandbox to prevent closures over this scope + let sandbox = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].getService()); + let factory = Cu.evalInSandbox("({ createInstance: function () this })", sandbox); + + factory.classID = Components.ID("{f541c8b0-fe26-4621-a30b-e77d21721fb5}"); + factory.contractID = BOOTSTRAP_CONTRACT; + factory.QueryInterface = XPCOMUtils.generateQI([Ci.nsIFactory]); + factory.wrappedJSObject = factory; + + manager.registerFactory(factory.classID, String(factory.classID), + BOOTSTRAP_CONTRACT, factory); + } Cc[BOOTSTRAP_CONTRACT].getService().wrappedJSObject.loader = !Cu.unload && JSMLoader; @@ -237,14 +269,19 @@ function init() { Services.obs.notifyObservers(null, "dactyl-rehash", null); updateVersion(); - require(global, "overlay"); + + updateLoader(); + if (addon !== addonData) + require(global, "main"); } function shutdown(data, reason) { - dump("dactyl: bootstrap: shutdown " + reasonToString(reason) + "\n"); + debug("bootstrap: shutdown " + reasonToString(reason)); if (reason != APP_SHUTDOWN) { try { - module("resource://dactyl-content/disable-acr.jsm").cleanup(); + module(DISABLE_ACR).cleanup(); + if (Cu.unload) + Cu.unload(DISABLE_ACR); } catch (e) { reportError(e); @@ -264,6 +301,18 @@ function shutdown(data, reason) { } } +function uninstall(data, reason) { + debug("bootstrap: uninstall " + reasonToString(reason)); + if (reason == ADDON_UNINSTALL) { + Services.prefs.deleteBranch("extensions.dactyl."); + + if (BOOTSTRAP_CONTRACT in Cc) { + let service = Cc[BOOTSTRAP_CONTRACT].getService().wrappedJSObject; + manager.unregisterFactory(service.classID, service); + } + } +} + function reasonToString(reason) { for each (let name in ["disable", "downgrade", "enable", "install", "shutdown", "startup", @@ -273,7 +322,6 @@ function reasonToString(reason) { return name; } -function install(data, reason) { dump("dactyl: bootstrap: install " + reasonToString(reason) + "\n"); } -function uninstall(data, reason) { dump("dactyl: bootstrap: uninstall " + reasonToString(reason) + "\n"); } +function install(data, reason) { debug("bootstrap: install " + reasonToString(reason)); } // vim: set fdm=marker sw=4 ts=4 et: diff --git a/common/chrome.manifest b/common/chrome.manifest index 4995b0e..3eae8e1 100644 --- a/common/chrome.manifest +++ b/common/chrome.manifest @@ -1,7 +1,9 @@ +resource dactyl-local ./ resource dactyl-local-content content/ resource dactyl-local-skin skin/ resource dactyl-local-locale locale/ +resource dactyl-common ../common/ resource dactyl ../common/modules/ resource dactyl-content ../common/content/ resource dactyl-skin ../common/skin/ @@ -13,10 +15,3 @@ component {16dc34f7-6d22-4aa4-a67f-2921fb5dcb69} components/commandline-handler. contract @mozilla.org/commandlinehandler/general-startup;1?type=dactyl {16dc34f7-6d22-4aa4-a67f-2921fb5dcb69} category command-line-handler m-dactyl @mozilla.org/commandlinehandler/general-startup;1?type=dactyl -component {c1b67a07-18f7-4e13-b361-2edcc35a5a0d} components/protocols.js -contract @mozilla.org/network/protocol;1?name=chrome-data {c1b67a07-18f7-4e13-b361-2edcc35a5a0d} -component {9c8f2530-51c8-4d41-b356-319e0b155c44} components/protocols.js -contract @mozilla.org/network/protocol;1?name=dactyl {9c8f2530-51c8-4d41-b356-319e0b155c44} -component {f4506a17-5b4d-4cd9-92d4-2eb4630dc388} components/protocols.js -contract @dactyl.googlecode.com/base/xpc-interface-shim {f4506a17-5b4d-4cd9-92d4-2eb4630dc388} - diff --git a/common/components/commandline-handler.js b/common/components/commandline-handler.js index 918d7bf..0fd1189 100644 --- a/common/components/commandline-handler.js +++ b/common/components/commandline-handler.js @@ -11,37 +11,72 @@ function reportError(e) { var global = this; var NAME = "command-line-handler"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +var { classes: Cc, interfaces: Ci, utils: Cu } = Components; Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +function init() { + Cu.import("resource://dactyl/bootstrap.jsm"); + if (!JSMLoader.initialized) + JSMLoader.init(); + JSMLoader.load("base.jsm", global); + require(global, "config"); + require(global, "util"); +} + function CommandLineHandler() { this.wrappedJSObject = this; - - Cu.import("resource://dactyl/base.jsm"); - require(global, "util"); - require(global, "config"); } CommandLineHandler.prototype = { - classDescription: "Dactyl Command-line Handler", + classDescription: "Dactyl command line Handler", classID: Components.ID("{16dc34f7-6d22-4aa4-a67f-2921fb5dcb69}"), contractID: "@mozilla.org/commandlinehandler/general-startup;1?type=dactyl", - _xpcom_categories: [{ - category: "command-line-handler", - entry: "m-dactyl" - }], + _xpcom_categories: [ + { + category: "command-line-handler", + entry: "m-dactyl" + }, - QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsICommandLineHandler]), + // FIXME: Belongs elsewhere + { + category: "profile-after-change", + entry: "m-dactyl" + } + ], + + observe: function observe(subject, topic, data) { + if (topic === "profile-after-change") { + init(); + require(global, "main"); + } + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsICommandLineHandler]), handle: function (commandLine) { + init(); + try { + var remote = commandLine.handleFlagWithParam(config.name + "-remote", false); + } + catch (e) { + util.dump("option '-" + config.name + "-remote' requires an argument\n"); + } + + try { + if (remote) { + commandLine.preventDefault = true; + require(global, "services"); + util.dactyl.execute(remote); + } + } + catch(e) { + util.reportError(e) + }; - // TODO: handle remote launches differently? try { this.optionValue = commandLine.handleFlagWithParam(config.name, false); } diff --git a/common/components/protocols.js b/common/components/protocols.js deleted file mode 100644 index 94eab5d..0000000 --- a/common/components/protocols.js +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (c) 2008-2010 Kris Maglione -// -// This work is licensed for reuse under an MIT license. Details are -// given in the LICENSE.txt file included with this file. -"use strict"; -function reportError(e) { - dump("dactyl: protocols: " + e + "\n" + (e.stack || Error().stack)); - Cu.reportError(e); -} - -/* Adds support for data: URIs with chrome privileges - * and fragment identifiers. - * - * "chrome-data:" [; ]* "," [] - * - * By Kris Maglione, ideas from Ed Anuff's nsChromeExtensionHandler. - */ - -var NAME = "protocols"; -var global = this; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; - -var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); -var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].getService(Ci.nsIPrincipal); - -var DNE = "resource://dactyl/content/does/not/exist"; -var _DNE; - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); - -function makeChannel(url, orig) { - try { - if (url == null) - return fakeChannel(orig); - - if (typeof url === "function") - return let ([type, data] = url(orig)) StringChannel(data, type, orig); - - if (isArray(url)) - return let ([type, data] = url) StringChannel(data, type, orig); - - let uri = ioService.newURI(url, null, null); - return (new XMLChannel(uri)).channel; - } - catch (e) { - util.reportError(e); - throw e; - } -} -function fakeChannel(orig) { - let channel = ioService.newChannel(DNE, null, null); - channel.originalURI = orig; - return channel; -} -function redirect(to, orig, time) { - let html = .toXMLString(); - return StringChannel(html, "text/html", ioService.newURI(to, null, null)); -} - -function Factory(clas) ({ - __proto__: clas.prototype, - createInstance: function (outer, iid) { - try { - if (outer != null) - throw Components.results.NS_ERROR_NO_AGGREGATION; - if (!clas.instance) - clas.instance = new clas(); - return clas.instance.QueryInterface(iid); - } - catch (e) { - reportError(e); - throw e; - } - } -}); - -function ChromeData() {} -ChromeData.prototype = { - contractID: "@mozilla.org/network/protocol;1?name=chrome-data", - classID: Components.ID("{c1b67a07-18f7-4e13-b361-2edcc35a5a0d}"), - classDescription: "Data URIs with chrome privileges", - QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]), - _xpcom_factory: Factory(ChromeData), - - scheme: "chrome-data", - defaultPort: -1, - allowPort: function (port, scheme) false, - protocolFlags: Ci.nsIProtocolHandler.URI_NORELATIVE - | Ci.nsIProtocolHandler.URI_NOAUTH - | Ci.nsIProtocolHandler.URI_IS_UI_RESOURCE, - - newURI: function (spec, charset, baseURI) { - var uri = Components.classes["@mozilla.org/network/standard-url;1"] - .createInstance(Components.interfaces.nsIStandardURL) - .QueryInterface(Components.interfaces.nsIURI); - uri.init(uri.URLTYPE_STANDARD, this.defaultPort, spec, charset, null); - return uri; - }, - - newChannel: function (uri) { - try { - if (uri.scheme == this.scheme) { - let channel = ioService.newChannel(uri.spec.replace(/^.*?:\/*(.*)(?:#.*)?/, "data:$1"), - null, null); - channel.contentCharset = "UTF-8"; - channel.owner = systemPrincipal; - channel.originalURI = uri; - return channel; - } - } - catch (e) {} - return fakeChannel(uri); - } -}; - -function Dactyl() { - // Kill stupid validator warning. - this["wrapped" + "JSObject"] = this; - - this.HELP_TAGS = {}; - this.FILE_MAP = {}; - this.OVERLAY_MAP = {}; - - this.pages = {}; - this.providers = {}; - - Cu.import("resource://dactyl/bootstrap.jsm"); - if (!JSMLoader.initialized) - JSMLoader.init(); - JSMLoader.load("base.jsm", global); - require(global, "config"); - require(global, "services"); - require(global, "util"); - _DNE = ioService.newChannel(DNE, null, null).name; - - // Doesn't belong here: - AboutHandler.prototype.register(); -} -Dactyl.prototype = { - contractID: "@mozilla.org/network/protocol;1?name=dactyl", - classID: Components.ID("{9c8f2530-51c8-4d41-b356-319e0b155c44}"), - classDescription: "Dactyl utility protocol", - QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsIProtocolHandler]), - _xpcom_factory: Factory(Dactyl), - - init: function (obj) { - for each (let prop in ["HELP_TAGS", "FILE_MAP", "OVERLAY_MAP"]) { - this[prop] = this[prop].constructor(); - for (let [k, v] in Iterator(obj[prop] || {})) - this[prop][k] = v; - } - this.initialized = true; - }, - - scheme: "dactyl", - defaultPort: -1, - allowPort: function (port, scheme) false, - protocolFlags: 0 - | Ci.nsIProtocolHandler.URI_IS_UI_RESOURCE - | Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE, - - newURI: function newURI(spec, charset, baseURI) { - var uri = Cc["@mozilla.org/network/standard-url;1"] - .createInstance(Ci.nsIStandardURL) - .QueryInterface(Ci.nsIURI); - if (baseURI && baseURI.host === "data") - baseURI = null; - uri.init(uri.URLTYPE_STANDARD, this.defaultPort, spec, charset, baseURI); - return uri; - }, - - newChannel: function newChannel(uri) { - try { - if (/^help/.test(uri.host) && !("all" in this.FILE_MAP)) - return redirect(uri.spec, uri, 1); - - if (uri.host in this.providers) - return makeChannel(this.providers[uri.host](uri), uri); - - let path = decodeURIComponent(uri.path.replace(/^\/|#.*/g, "")); - switch(uri.host) { - case "content": - return makeChannel(this.pages[path] || "resource://dactyl-content/" + path, uri); - case "data": - try { - var channel = ioService.newChannel(uri.path.replace(/^\/(.*)(?:#.*)?/, "data:$1"), - null, null); - } - catch (e) { - var error = e; - break; - } - channel.contentCharset = "UTF-8"; - channel.owner = systemPrincipal; - channel.originalURI = uri; - return channel; - case "help": - return makeChannel(this.FILE_MAP[path], uri); - case "help-overlay": - return makeChannel(this.OVERLAY_MAP[path], uri); - case "help-tag": - let tag = decodeURIComponent(uri.path.substr(1)); - if (tag in this.FILE_MAP) - return redirect("dactyl://help/" + tag, uri); - if (tag in this.HELP_TAGS) - return redirect("dactyl://help/" + this.HELP_TAGS[tag] + "#" + tag.replace(/#/g, encodeURIComponent), uri); - break; - case "locale": - return LocaleChannel("dactyl-locale", path, uri); - case "locale-local": - return LocaleChannel("dactyl-local-locale", path, uri); - } - } - catch (e) { - util.reportError(e); - } - if (error) - throw error; - return fakeChannel(uri); - }, - - // FIXME: Belongs elsewhere - _xpcom_categories: [{ - category: "profile-after-change", - entry: "m-dactyl" - }], - - observe: function observe(subject, topic, data) { - if (topic === "profile-after-change") { - Cu.import("resource://dactyl/bootstrap.jsm"); - JSMLoader.init(); - require(global, "overlay"); - } - } -}; - -function LocaleChannel(pkg, path, orig) { - for each (let locale in [config.locale, "en-US"]) - for each (let sep in "-/") { - var channel = makeChannel(["resource:/", pkg + sep + config.locale, path].join("/"), orig); - if (channel.name !== _DNE) - return channel; - } - return channel; -} - -function StringChannel(data, contentType, uri) { - let channel = services.StreamChannel(uri); - channel.contentStream = services.CharsetConv("UTF-8").convertToInputStream(data); - if (contentType) - channel.contentType = contentType; - channel.contentCharset = "UTF-8"; - channel.owner = systemPrincipal; - if (uri) - channel.originalURI = uri; - return channel; -} - -function XMLChannel(uri, contentType) { - try { - var channel = services.io.newChannelFromURI(uri); - var channelStream = channel.open(); - } - catch (e) { - this.channel = fakeChannel(uri); - return; - } - - this.uri = uri; - this.sourceChannel = services.io.newChannelFromURI(uri); - this.pipe = services.Pipe(true, true, 0, 0, null); - this.writes = []; - - this.channel = services.StreamChannel(uri); - this.channel.contentStream = this.pipe.inputStream; - this.channel.contentType = contentType || channel.contentType; - this.channel.contentCharset = "UTF-8"; - this.channel.owner = systemPrincipal; - - let stream = services.InputStream(channelStream); - let [, pre, doctype, url, open, post] = util.regexp(, "x").exec(stream.read(4096)); - this.writes.push(pre); - if (doctype) { - this.writes.push(doctype + "[\n"); - try { - this.writes.push(services.io.newChannel(url, null, null).open()); - } - catch (e) {} - if (!open) - this.writes.push("\n]"); - this.writes.push(post); - } - this.writes.push(channelStream); - - this.writeNext(); -} -XMLChannel.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver]), - writeNext: function () { - try { - if (!this.writes.length) - this.pipe.outputStream.close(); - else { - let stream = this.writes.shift(); - if (isString(stream)) - stream = services.StringStream(stream); - - services.StreamCopier(stream, this.pipe.outputStream, null, - false, true, 4096, true, false) - .asyncCopy(this, null); - } - } - catch (e) { - util.reportError(e); - } - }, - - onStartRequest: function (request, context) {}, - onStopRequest: function (request, context, statusCode) { - this.writeNext(); - } -}; - -function AboutHandler() {} -AboutHandler.prototype = { - register: function () { - try { - JSMLoader.registerFactory(Factory(AboutHandler)); - } - catch (e) { - util.reportError(e); - } - }, - - get classDescription() "About " + config.appName + " Page", - - classID: Components.ID("81495d80-89ee-4c36-a88d-ea7c4e5ac63f"), - - get contractID() "@mozilla.org/network/protocol/about;1?what=" + config.name, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]), - - newChannel: function (uri) { - let channel = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService) - .newChannel("dactyl://content/about.xul", null, null); - channel.originalURI = uri; - return channel; - }, - - getURIFlags: function (uri) Ci.nsIAboutModule.ALLOW_SCRIPT, -}; - -// A hack to get information about interfaces. -// Doesn't belong here. -function Shim() {} -Shim.prototype = { - contractID: "@dactyl.googlecode.com/base/xpc-interface-shim", - classID: Components.ID("{f4506a17-5b4d-4cd9-92d4-2eb4630dc388}"), - classDescription: "XPCOM empty interface shim", - QueryInterface: function (iid) { - if (iid.equals(Ci.nsISecurityCheckedComponent)) - throw Components.results.NS_ERROR_NO_INTERFACE; - return this; - }, - getHelperForLanguage: function () null, - getInterfaces: function (count) { count.value = 0; } -}; - -if (XPCOMUtils.generateNSGetFactory) - var NSGetFactory = XPCOMUtils.generateNSGetFactory([ChromeData, Dactyl, Shim]); -else - var NSGetModule = XPCOMUtils.generateNSGetModule([ChromeData, Dactyl, Shim]); -var EXPORTED_SYMBOLS = ["NSGetFactory", "global"]; - -// vim: set fdm=marker sw=4 ts=4 et: diff --git a/common/config.json b/common/config.json new file mode 100644 index 0000000..f9aee18 --- /dev/null +++ b/common/config.json @@ -0,0 +1,38 @@ +{ + "completers": { + "abbreviation": "abbreviation", + "altstyle": "alternateStyleSheet", + "bookmark": "bookmark", + "buffer": "buffer", + "charset": "charset", + "color": "colorScheme", + "command": "command", + "dialog": "dialog", + "dir": "directory", + "environment": "environment", + "event": "autocmdEvent", + "extension": "extension", + "file": "file", + "help": "help", + "highlight": "highlightGroup", + "history": "history", + "javascript": "javascript", + "macro": "macro", + "mapping": "userMapping", + "mark": "mark", + "menu": "menuItem", + "option": "option", + "preference": "preference", + "qmark": "quickmark", + "runtime": "runtime", + "search": "search", + "shellcmd": "shellCommand", + "toolbar": "toolbar", + "url": "url", + "usercommand": "userCommand" + }, + + "option-defaults": { + "guioptions": "rb" + } +} diff --git a/common/content/abbreviations.js b/common/content/abbreviations.js index 71e6c93..0829497 100644 --- a/common/content/abbreviations.js +++ b/common/content/abbreviations.js @@ -4,7 +4,7 @@ // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. -"use strict"; +/* use strict */ /** @scope modules */ @@ -350,7 +350,9 @@ var Abbreviations = Module("abbreviations", { command: this.name, arguments: [abbr.lhs], literalArg: abbr.rhs, - options: callable(abbr.rhs) ? {"-javascript": null} : {} + options: { + "-javascript": abbr.rhs ? null : undefined + } } for ([, abbr] in Iterator(abbreviations.user.merged)) if (abbr.modesEqual(modes)) diff --git a/common/content/about.xul b/common/content/about.xul index 433402c..aba640b 100644 --- a/common/content/about.xul +++ b/common/content/about.xul @@ -6,7 +6,7 @@ -