Merge mozilla-inbound and mozilla-central

This commit is contained in:
Ehsan Akhgari 2011-09-08 16:57:20 -04:00
commit 59d59bfe73
87 changed files with 2322 additions and 1053 deletions

View File

@ -734,19 +734,11 @@ pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
// the database.
pref("urlclassifier.confirm-age", 2700);
#ifdef MOZ_WIDGET_GTK2
#define RESTRICT_CACHEMAX
#endif
#ifdef XP_OS2
#define RESTRICT_CACHEMAX
#endif
// Maximum size of the sqlite3 cache during an update, in bytes
#ifdef RESTRICT_CACHEMAX
pref("urlclassifier.updatecachemax", 104857600);
#else
pref("urlclassifier.updatecachemax", -1);
#endif
pref("urlclassifier.updatecachemax", 41943040);
// Maximum size of the sqlite3 cache for lookups, in bytes
pref("urlclassifier.lookupcachemax", 1048576);
// URL for checking the reason for a malware warning.
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");

View File

@ -10,7 +10,7 @@
#endif
>
<uses-sdk android:minSdkVersion="5"
android:targetSdkVersion="5"/>
android:targetSdkVersion="11"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

View File

@ -15,20 +15,20 @@
android:layout_height="25dp"
android:scaleType="fitCenter" />
<TextView android:id="@+id/notificationTitle"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:textStyle="bold"
android:textSize="18sp"
android:paddingLeft="4dp"
android:textColor="#ff000000" />
/>
</LinearLayout>
<TextView android:id="@+id/notificationText"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="4dp"
android:textColor="#ff000000" />
/>
</LinearLayout>

View File

@ -16,16 +16,15 @@
android:layout_height="25dp"
android:scaleType="fitCenter" />
<TextView android:id="@+id/notificationTitle"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:textStyle="bold"
android:textSize="18sp"
android:paddingLeft="10dp"
android:textColor="#ff000000" />
/>
</LinearLayout>
<LinearLayout
@ -34,10 +33,11 @@
android:orientation="horizontal"
>
<TextView android:id="@+id/notificationText"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="3dp"
android:textColor="#ff000000" />
/>
<ProgressBar android:id="@+id/notificationProgressbar"
style="?android:attr/progressBarStyleHorizontal"

View File

@ -15,16 +15,15 @@
android:layout_height="25dp"
android:scaleType="fitCenter" />
<TextView android:id="@+id/notificationTitle"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:textStyle="bold"
android:textSize="18sp"
android:paddingLeft="4dp"
android:textColor="#ff000000" />
/>
</LinearLayout>
<ProgressBar android:id="@+id/notificationProgressbar"
@ -38,9 +37,10 @@
android:layout_centerHorizontal="true" />
<TextView android:id="@+id/notificationText"
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="4dp"
android:textColor="#ff000000" />
/>
</LinearLayout>

View File

@ -130,6 +130,17 @@ void Histogram::Add(int value) {
Accumulate(value, 1, index);
}
void Histogram::Subtract(int value) {
if (value > kSampleType_MAX - 1)
value = kSampleType_MAX - 1;
if (value < 0)
value = 0;
size_t index = BucketIndex(value);
DCHECK_GE(value, ranges(index));
DCHECK_LT(value, ranges(index + 1));
Accumulate(value, -1, index);
}
void Histogram::AddBoolean(bool value) {
DCHECK(false);
}

View File

@ -381,6 +381,7 @@ class Histogram {
Flags flags);
void Add(int value);
void Subtract(int value);
// This method is an interface, used only by BooleanHistogram.
virtual void AddBoolean(bool value);

View File

@ -155,6 +155,7 @@ CPPSRCS = \
jsxml.cpp \
prmjtime.cpp \
sharkctl.cpp \
CallObject.cpp \
Debugger.cpp \
GlobalObject.cpp \
Stack.cpp \
@ -247,6 +248,7 @@ EXPORTS_NAMESPACES = vm
EXPORTS_vm = \
ArgumentsObject.h \
CallObject.h \
GlobalObject.h \
Stack.h \
String.h \

View File

@ -72,6 +72,7 @@
#include "jsexn.h"
#include "jsstaticcheck.h"
#include "jstracer.h"
#include "vm/CallObject.h"
#include "vm/Debugger.h"
#if JS_HAS_GENERATORS
@ -91,7 +92,7 @@
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
#include "vm/CallObject-inl.h"
#include "vm/ArgumentsObject-inl.h"
#include "vm/Stack-inl.h"
@ -283,7 +284,7 @@ js_GetArgsObject(JSContext *cx, StackFrame *fp)
if (argsobj->isStrictArguments())
fp->forEachCanonicalActualArg(PutArg(argsobj->data()->slots));
else
argsobj->setPrivate(fp);
argsobj->setStackFrame(fp);
fp->setArgsObj(*argsobj);
return argsobj;
@ -294,11 +295,11 @@ js_PutArgsObject(StackFrame *fp)
{
ArgumentsObject &argsobj = fp->argsObj();
if (argsobj.isNormalArguments()) {
JS_ASSERT(argsobj.getPrivate() == fp);
JS_ASSERT(argsobj.maybeStackFrame() == fp);
fp->forEachCanonicalActualArg(PutArg(argsobj.data()->slots));
argsobj.setPrivate(NULL);
argsobj.setStackFrame(NULL);
} else {
JS_ASSERT(!argsobj.getPrivate());
JS_ASSERT(!argsobj.maybeStackFrame());
}
}
@ -319,9 +320,9 @@ js_NewArgumentsOnTrace(JSContext *cx, uint32 argc, JSObject *callee)
* Strict mode callers must copy arguments into the created arguments
* object. The trace-JITting code is in TraceRecorder::newArguments.
*/
JS_ASSERT(!argsobj->getPrivate());
JS_ASSERT(!argsobj->maybeStackFrame());
} else {
argsobj->setPrivate(JS_ARGUMENTS_OBJECT_ON_TRACE);
argsobj->setOnTrace();
}
return argsobj;
@ -335,7 +336,7 @@ js_PutArgumentsOnTrace(JSContext *cx, JSObject *obj, Value *argv)
{
NormalArgumentsObject *argsobj = obj->asNormalArguments();
JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE);
JS_ASSERT(argsobj->onTrace());
/*
* TraceRecorder::putActivationObjects builds a single, contiguous array of
@ -349,7 +350,7 @@ js_PutArgumentsOnTrace(JSContext *cx, JSObject *obj, Value *argv)
*dst = *src;
}
argsobj->setPrivate(NULL);
argsobj->clearOnTrace();
return true;
}
JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArgumentsOnTrace, CONTEXT, OBJECT, VALUEPTR, 0,
@ -390,7 +391,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
uintN arg = uintN(JSID_TO_INT(id));
if (arg < argsobj->initialLength()) {
JS_ASSERT(!argsobj->element(arg).isMagic(JS_ARGS_HOLE));
if (StackFrame *fp = reinterpret_cast<StackFrame *>(argsobj->getPrivate()))
if (StackFrame *fp = argsobj->maybeStackFrame())
*vp = fp->canonicalActualArg(arg);
else
*vp = argsobj->element(arg);
@ -427,7 +428,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
if (JSID_IS_INT(id)) {
uintN arg = uintN(JSID_TO_INT(id));
if (arg < argsobj->initialLength()) {
if (StackFrame *fp = reinterpret_cast<StackFrame *>(argsobj->getPrivate())) {
if (StackFrame *fp = argsobj->maybeStackFrame()) {
JSScript *script = fp->functionScript();
if (script->usesArguments) {
if (arg < fp->numFormalArgs())
@ -673,7 +674,7 @@ static void
args_trace(JSTracer *trc, JSObject *obj)
{
ArgumentsObject *argsobj = obj->asArguments();
if (argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE) {
if (argsobj->onTrace()) {
JS_ASSERT(!argsobj->isStrictArguments());
return;
}
@ -757,57 +758,6 @@ Class js::DeclEnvClass = {
ConvertStub
};
/*
* Construct a call object for the given bindings. If this is a call object
* for a function invocation, callee should be the function being called.
* Otherwise it must be a call object for eval of strict mode code, and callee
* must be null.
*/
static JSObject *
NewCallObject(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee)
{
Bindings &bindings = script->bindings;
size_t argsVars = bindings.countArgsAndVars();
size_t slots = JSObject::CALL_RESERVED_SLOTS + argsVars;
gc::AllocKind kind = gc::GetGCObjectKind(slots);
/*
* Make sure that the arguments and variables in the call object all end up
* in a contiguous range of slots. We need this to be able to embed the
* args/vars arrays in the TypeScriptNesting for the function, after the
* call object's frame has finished.
*/
if (cx->typeInferenceEnabled() && gc::GetGCKindSlots(kind) < slots) {
kind = gc::GetGCObjectKind(JSObject::CALL_RESERVED_SLOTS);
JS_ASSERT(gc::GetGCKindSlots(kind) == JSObject::CALL_RESERVED_SLOTS);
}
JSObject *callobj = js_NewGCObject(cx, kind);
if (!callobj)
return NULL;
/* Init immediately to avoid GC seeing a half-init'ed object. */
callobj->initCall(cx, bindings, &scopeChain);
callobj->makeVarObj();
/* This must come after callobj->lastProp has been set. */
if (!callobj->ensureInstanceReservedSlots(cx, argsVars))
return NULL;
#ifdef DEBUG
for (Shape::Range r = callobj->lastProp; !r.empty(); r.popFront()) {
const Shape &s = r.front();
if (s.slot != SHAPE_INVALID_SLOT) {
JS_ASSERT(s.slot + 1 == callobj->slotSpan());
break;
}
}
#endif
callobj->setCallObjCallee(callee);
return callobj;
}
static inline JSObject *
NewDeclEnvObject(JSContext *cx, StackFrame *fp)
{
@ -826,7 +776,7 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp)
namespace js {
JSObject *
CallObject *
CreateFunCallObject(JSContext *cx, StackFrame *fp)
{
JS_ASSERT(fp->isNonEvalFunctionFrame());
@ -852,23 +802,23 @@ CreateFunCallObject(JSContext *cx, StackFrame *fp)
}
}
JSObject *callobj = NewCallObject(cx, fp->script(), *scopeChain, &fp->callee());
CallObject *callobj = CallObject::create(cx, fp->script(), *scopeChain, &fp->callee());
if (!callobj)
return NULL;
callobj->setPrivate(fp);
callobj->setStackFrame(fp);
fp->setScopeChainWithOwnCallObj(*callobj);
return callobj;
}
JSObject *
CallObject *
CreateEvalCallObject(JSContext *cx, StackFrame *fp)
{
JSObject *callobj = NewCallObject(cx, fp->script(), fp->scopeChain(), NULL);
CallObject *callobj = CallObject::create(cx, fp->script(), fp->scopeChain(), NULL);
if (!callobj)
return NULL;
callobj->setPrivate(fp);
callobj->setStackFrame(fp);
fp->setScopeChainWithOwnCallObj(*callobj);
return callobj;
}
@ -881,52 +831,44 @@ js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSO
JS_ASSERT(!js_IsNamedLambda(fun));
JS_ASSERT(scopeChain);
JS_ASSERT(callee);
return NewCallObject(cx, fun->script(), *scopeChain, callee);
return CallObject::create(cx, fun->script(), *scopeChain, callee);
}
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT,
0, nanojit::ACCSET_STORE_ANY)
inline static void
CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
{
JS_ASSERT(callobj.numSlots() >= JSObject::CALL_RESERVED_SLOTS + nargs + nvars);
callobj.copySlotRange(JSObject::CALL_RESERVED_SLOTS, argv, nargs);
callobj.copySlotRange(JSObject::CALL_RESERVED_SLOTS + nargs, slots, nvars);
}
void
js_PutCallObject(StackFrame *fp)
{
JSObject &callobj = fp->callObj();
JS_ASSERT(callobj.getPrivate() == fp);
CallObject &callobj = fp->callObj().asCall();
JS_ASSERT(callobj.maybeStackFrame() == fp);
JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame());
JS_ASSERT(fp->isEvalFrame() == callobj.callIsForEval());
JS_ASSERT(fp->isEvalFrame() == callobj.isForEval());
/* Get the arguments object to snapshot fp's actual argument values. */
if (fp->hasArgsObj()) {
if (!fp->hasOverriddenArgs())
callobj.setCallObjArguments(ObjectValue(fp->argsObj()));
callobj.setArguments(ObjectValue(fp->argsObj()));
js_PutArgsObject(fp);
}
JSScript *script = fp->script();
Bindings &bindings = script->bindings;
if (callobj.callIsForEval()) {
if (callobj.isForEval()) {
JS_ASSERT(script->strictModeCode);
JS_ASSERT(bindings.countArgs() == 0);
/* This could be optimized as below, but keep it simple for now. */
CopyValuesToCallObject(callobj, 0, NULL, bindings.countVars(), fp->slots());
callobj.copyValues(0, NULL, bindings.countVars(), fp->slots());
} else {
JSFunction *fun = fp->fun();
JS_ASSERT(fun == callobj.getCallObjCalleeFunction());
JS_ASSERT(fun == callobj.getCalleeFunction());
JS_ASSERT(script == fun->script());
uintN n = bindings.countArgsAndVars();
if (n > 0) {
JS_ASSERT(JSObject::CALL_RESERVED_SLOTS + n <= callobj.numSlots());
JS_ASSERT(CallObject::RESERVED_SLOTS + n <= callobj.numSlots());
uint32 nvars = bindings.countVars();
uint32 nargs = bindings.countArgs();
@ -939,7 +881,7 @@ js_PutCallObject(StackFrame *fp)
|| script->debugMode
#endif
) {
CopyValuesToCallObject(callobj, nargs, fp->formalArgs(), nvars, fp->slots());
callobj.copyValues(nargs, fp->formalArgs(), nvars, fp->slots());
} else {
/*
* For each arg & var that is closed over, copy it from the stack
@ -948,13 +890,13 @@ js_PutCallObject(StackFrame *fp)
uint32 nclosed = script->nClosedArgs;
for (uint32 i = 0; i < nclosed; i++) {
uint32 e = script->getClosedArg(i);
callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + e, fp->formalArg(e));
callobj.setArg(e, fp->formalArg(e));
}
nclosed = script->nClosedVars;
for (uint32 i = 0; i < nclosed; i++) {
uint32 e = script->getClosedVar(i);
callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + nargs + e, fp->slots()[e]);
callobj.setVar(e, fp->slots()[e]);
}
}
@ -964,8 +906,8 @@ js_PutCallObject(StackFrame *fp)
*/
types::TypeScriptNesting *nesting = script->nesting();
if (nesting && script->isOuterFunction) {
nesting->argArray = callobj.callObjArgArray();
nesting->varArray = callobj.callObjVarArray();
nesting->argArray = callobj.argArray();
nesting->varArray = callobj.varArray();
}
}
@ -979,19 +921,19 @@ js_PutCallObject(StackFrame *fp)
}
}
callobj.setPrivate(NULL);
callobj.setStackFrame(NULL);
}
JSBool JS_FASTCALL
js_PutCallObjectOnTrace(JSObject *callobj, uint32 nargs, Value *argv,
js_PutCallObjectOnTrace(JSObject *obj, uint32 nargs, Value *argv,
uint32 nvars, Value *slots)
{
JS_ASSERT(callobj->isCall());
JS_ASSERT(!callobj->getPrivate());
CallObject &callobj = obj->asCall();
JS_ASSERT(!callobj.maybeStackFrame());
uintN n = nargs + nvars;
if (n != 0)
CopyValuesToCallObject(*callobj, nargs, argv, nvars, slots);
callobj.copyValues(nargs, argv, nvars, slots);
return true;
}
@ -1004,14 +946,16 @@ namespace js {
static JSBool
GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
StackFrame *fp = obj->maybeCallObjStackFrame();
CallObject &callobj = obj->asCall();
StackFrame *fp = callobj.maybeStackFrame();
if (fp && !fp->hasOverriddenArgs()) {
JSObject *argsobj = js_GetArgsObject(cx, fp);
if (!argsobj)
return false;
vp->setObject(*argsobj);
} else {
*vp = obj->getCallObjArguments();
*vp = callobj.getArguments();
}
return true;
}
@ -1019,37 +963,41 @@ GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
static JSBool
SetCallArguments(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
{
if (StackFrame *fp = obj->maybeCallObjStackFrame())
CallObject &callobj = obj->asCall();
if (StackFrame *fp = callobj.maybeStackFrame())
fp->setOverriddenArgs();
obj->setCallObjArguments(*vp);
callobj.setArguments(*vp);
return true;
}
JSBool
GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
CallObject &callobj = obj->asCall();
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
if (StackFrame *fp = obj->maybeCallObjStackFrame())
if (StackFrame *fp = callobj.maybeStackFrame())
*vp = fp->formalArg(i);
else
*vp = obj->callObjArg(i);
*vp = callobj.arg(i);
return true;
}
JSBool
SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
{
CallObject &callobj = obj->asCall();
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
if (StackFrame *fp = obj->maybeCallObjStackFrame())
if (StackFrame *fp = callobj.maybeStackFrame())
fp->formalArg(i) = *vp;
else
obj->setCallObjArg(i, *vp);
callobj.setArg(i, *vp);
JSFunction *fun = obj->getCallObjCalleeFunction();
JSFunction *fun = callobj.getCalleeFunction();
JSScript *script = fun->script();
if (!script->ensureHasTypes(cx, fun))
return false;
@ -1062,40 +1010,43 @@ SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
JSBool
GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
CallObject &callobj = obj->asCall();
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
*vp = obj->getCallObjCallee()->getFlatClosureUpvar(i);
*vp = callobj.getCallee()->getFlatClosureUpvar(i);
return true;
}
JSBool
SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
{
CallObject &callobj = obj->asCall();
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
obj->getCallObjCallee()->setFlatClosureUpvar(i, *vp);
callobj.getCallee()->setFlatClosureUpvar(i, *vp);
return true;
}
JSBool
GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
CallObject &callobj = obj->asCall();
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
if (StackFrame *fp = obj->maybeCallObjStackFrame())
if (StackFrame *fp = callobj.maybeStackFrame())
*vp = fp->varSlot(i);
else
*vp = obj->callObjVar(i);
*vp = callobj.var(i);
return true;
}
JSBool
SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
{
JS_ASSERT(obj->isCall());
CallObject &callobj = obj->asCall();
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
@ -1115,12 +1066,12 @@ SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
}
#endif
if (StackFrame *fp = obj->maybeCallObjStackFrame())
if (StackFrame *fp = callobj.maybeStackFrame())
fp->varSlot(i) = *vp;
else
obj->setCallObjVar(i, *vp);
callobj.setVar(i, *vp);
JSFunction *fun = obj->getCallObjCalleeFunction();
JSFunction *fun = callobj.getCalleeFunction();
JSScript *script = fun->script();
if (!script->ensureHasTypes(cx, fun))
return false;
@ -1153,16 +1104,14 @@ JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallVar, CONTEXT, OBJECT, JSID, VALUE,
#endif
static JSBool
call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JSObject **objp)
call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
{
JS_ASSERT(obj->isCall());
JS_ASSERT(!obj->getProto());
if (!JSID_IS_ATOM(id))
return true;
JSObject *callee = obj->getCallObjCallee();
JSObject *callee = obj->asCall().getCallee();
#ifdef DEBUG
if (callee) {
JSScript *script = callee->getFunctionPrivate()->script();
@ -1204,7 +1153,7 @@ call_trace(JSTracer *trc, JSObject *obj)
JS_PUBLIC_DATA(Class) js::CallClass = {
"Call",
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS) |
JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS) |
JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS,
PropertyStub, /* addProperty */
PropertyStub, /* delProperty */

View File

@ -503,10 +503,10 @@ js_PutCallObjectOnTrace(JSObject *scopeChain, uint32 nargs, js::Value *argv,
namespace js {
JSObject *
CallObject *
CreateFunCallObject(JSContext *cx, StackFrame *fp);
JSObject *
CallObject *
CreateEvalCallObject(JSContext *cx, StackFrame *fp);
extern JSBool

View File

@ -95,6 +95,7 @@
#include "jsobjinlines.h"
#include "vm/String-inl.h"
#include "vm/CallObject-inl.h"
#ifdef MOZ_VALGRIND
# define JS_VALGRIND

View File

@ -5055,8 +5055,8 @@ TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
* The scope object must be the initial one for the script, before any call
* object has been created in the heavyweight case.
*/
JS_ASSERT_IF(scope && scope->isCall() && !scope->callIsForEval(),
scope->getCallObjCalleeFunction() != fun);
JS_ASSERT_IF(scope && scope->isCall() && !scope->asCall().isForEval(),
scope->asCall().getCalleeFunction() != fun);
if (!script->compileAndGo) {
script->types->global = NULL;
@ -5089,11 +5089,13 @@ TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
while (!scope->isCall())
scope = scope->getParent();
CallObject &call = scope->asCall();
/* The isInnerFunction test ensures there is no intervening strict eval call object. */
JS_ASSERT(!scope->callIsForEval());
JS_ASSERT(!call.isForEval());
/* Don't track non-heavyweight parents, NAME ops won't reach into them. */
JSFunction *parentFun = scope->getCallObjCalleeFunction();
JSFunction *parentFun = call.getCalleeFunction();
if (!parentFun || !parentFun->isHeavyweight())
return true;
JSScript *parent = parentFun->script();
@ -5121,8 +5123,8 @@ TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
if (!SetScope(cx, parent, scope->getParent()))
return false;
parent->nesting()->activeCall = scope;
parent->nesting()->argArray = scope->callObjArgArray();
parent->nesting()->varArray = scope->callObjVarArray();
parent->nesting()->argArray = call.argArray();
parent->nesting()->varArray = call.varArray();
}
JS_ASSERT(!script->types->nesting);
@ -5212,7 +5214,7 @@ CheckNestingParent(JSContext *cx, JSObject *scope, JSScript *script)
JSScript *parent = script->nesting()->parent;
JS_ASSERT(parent);
while (!scope->isCall() || scope->getCallObjCalleeFunction()->script() != parent)
while (!scope->isCall() || scope->asCall().getCalleeFunction()->script() != parent)
scope = scope->getParent();
if (scope != parent->nesting()->activeCall) {

View File

@ -55,7 +55,7 @@ namespace js {
namespace analyze {
class ScriptAnalysis;
}
struct GlobalObject;
class GlobalObject;
}
namespace js {

View File

@ -3900,7 +3900,7 @@ BEGIN_CASE(JSOP_GETELEM)
if (arg < argsobj->initialLength()) {
copyFrom = &argsobj->element(arg);
if (!copyFrom->isMagic(JS_ARGS_HOLE)) {
if (StackFrame *afp = reinterpret_cast<StackFrame *>(argsobj->getPrivate()))
if (StackFrame *afp = argsobj->maybeStackFrame())
copyFrom = &afp->canonicalActualArg(arg);
goto end_getelem;
}

View File

@ -4491,7 +4491,7 @@ JSObject::growSlots(JSContext *cx, size_t newcap)
* stack (and an eval, DEFFUN, etc. happens). We thus do not need to
* worry about updating any active outer function args/vars.
*/
JS_ASSERT_IF(isCall(), maybeCallObjStackFrame() != NULL);
JS_ASSERT_IF(isCall(), asCall().maybeStackFrame() != NULL);
/*
* When an object with CAPACITY_DOUBLING_MAX or fewer slots needs to

View File

@ -66,6 +66,7 @@ namespace js {
class AutoPropDescArrayRooter;
class JSProxyHandler;
class RegExp;
class CallObject;
struct GCMarker;
struct NativeIterator;
@ -733,6 +734,8 @@ struct JSObject : js::gc::Cell {
private:
inline js::Value* fixedSlots() const;
protected:
inline bool hasContiguousSlots(size_t start, size_t count) const;
public:
@ -1065,58 +1068,10 @@ struct JSObject : js::gc::Cell {
inline js::NormalArgumentsObject *asNormalArguments();
inline js::StrictArgumentsObject *asStrictArguments();
private:
/*
* Reserved slot structure for Call objects:
*
* private - the stack frame corresponding to the Call object
* until js_PutCallObject or its on-trace analog
* is called, null thereafter
* JSSLOT_CALL_CALLEE - callee function for the stack frame, or null if
* the stack frame is for strict mode eval code
* JSSLOT_CALL_ARGUMENTS - arguments object for non-strict mode eval stack
* frames (not valid for strict mode eval frames)
*/
static const uint32 JSSLOT_CALL_CALLEE = 0;
static const uint32 JSSLOT_CALL_ARGUMENTS = 1;
public:
inline js::CallObject &asCall();
public:
/* Number of reserved slots. */
static const uint32 CALL_RESERVED_SLOTS = 2;
/* True if this is for a strict mode eval frame or for a function call. */
inline bool callIsForEval() const;
/* The stack frame for this Call object, if the frame is still active. */
inline js::StackFrame *maybeCallObjStackFrame() const;
/*
* The callee function if this Call object was created for a function
* invocation, or null if it was created for a strict mode eval frame.
*/
inline JSObject *getCallObjCallee() const;
inline JSFunction *getCallObjCalleeFunction() const;
inline void setCallObjCallee(JSObject *callee);
inline const js::Value &getCallObjArguments() const;
inline void setCallObjArguments(const js::Value &v);
/* Returns the formal argument at the given index. */
inline const js::Value &callObjArg(uintN i) const;
inline void setCallObjArg(uintN i, const js::Value &v);
/* Returns the variable at the given index. */
inline const js::Value &callObjVar(uintN i) const;
inline void setCallObjVar(uintN i, const js::Value &v);
/*
* Get the actual arrays of arguments and variables. Only call if type
* inference is enabled, where we ensure that call object variables are in
* contiguous slots (see NewCallObject).
*/
inline js::Value *callObjArgArray();
inline js::Value *callObjVarArray();
/*
* Date-specific getters and setters.
*/
@ -1926,10 +1881,7 @@ IsCacheableNonGlobalScope(JSObject *obj)
{
JS_ASSERT(obj->getParent());
js::Class *clasp = obj->getClass();
bool cacheable = (clasp == &CallClass ||
clasp == &BlockClass ||
clasp == &DeclEnvClass);
bool cacheable = (obj->isCall() || obj->isBlock() || obj->isDeclEnv());
JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
return cacheable;

View File

@ -540,112 +540,6 @@ JSObject::denseArrayHasInlineSlots() const
return slots == fixedSlots();
}
inline bool
JSObject::callIsForEval() const
{
JS_ASSERT(isCall());
JS_ASSERT(getFixedSlot(JSSLOT_CALL_CALLEE).isObjectOrNull());
JS_ASSERT_IF(getFixedSlot(JSSLOT_CALL_CALLEE).isObject(),
getFixedSlot(JSSLOT_CALL_CALLEE).toObject().isFunction());
return getFixedSlot(JSSLOT_CALL_CALLEE).isNull();
}
inline js::StackFrame *
JSObject::maybeCallObjStackFrame() const
{
JS_ASSERT(isCall());
return reinterpret_cast<js::StackFrame *>(getPrivate());
}
inline void
JSObject::setCallObjCallee(JSObject *callee)
{
JS_ASSERT(isCall());
JS_ASSERT_IF(callee, callee->isFunction());
setFixedSlot(JSSLOT_CALL_CALLEE, js::ObjectOrNullValue(callee));
}
inline JSObject *
JSObject::getCallObjCallee() const
{
JS_ASSERT(isCall());
return getFixedSlot(JSSLOT_CALL_CALLEE).toObjectOrNull();
}
inline JSFunction *
JSObject::getCallObjCalleeFunction() const
{
JS_ASSERT(isCall());
return getFixedSlot(JSSLOT_CALL_CALLEE).toObject().getFunctionPrivate();
}
inline const js::Value &
JSObject::getCallObjArguments() const
{
JS_ASSERT(isCall());
JS_ASSERT(!callIsForEval());
return getFixedSlot(JSSLOT_CALL_ARGUMENTS);
}
inline void
JSObject::setCallObjArguments(const js::Value &v)
{
JS_ASSERT(isCall());
JS_ASSERT(!callIsForEval());
setFixedSlot(JSSLOT_CALL_ARGUMENTS, v);
}
inline const js::Value &
JSObject::callObjArg(uintN i) const
{
JS_ASSERT(isCall());
JS_ASSERT(i < getCallObjCalleeFunction()->nargs);
return getSlot(JSObject::CALL_RESERVED_SLOTS + i);
}
inline void
JSObject::setCallObjArg(uintN i, const js::Value &v)
{
JS_ASSERT(isCall());
JS_ASSERT(i < getCallObjCalleeFunction()->nargs);
setSlot(JSObject::CALL_RESERVED_SLOTS + i, v);
}
inline js::Value *
JSObject::callObjArgArray()
{
js::DebugOnly<JSFunction*> fun = getCallObjCalleeFunction();
JS_ASSERT(hasContiguousSlots(JSObject::CALL_RESERVED_SLOTS, fun->nargs));
return getSlotAddress(JSObject::CALL_RESERVED_SLOTS);
}
inline const js::Value &
JSObject::callObjVar(uintN i) const
{
JSFunction *fun = getCallObjCalleeFunction();
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
JS_ASSERT(i < fun->script()->bindings.countVars());
return getSlot(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i);
}
inline void
JSObject::setCallObjVar(uintN i, const js::Value &v)
{
JSFunction *fun = getCallObjCalleeFunction();
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
JS_ASSERT(i < fun->script()->bindings.countVars());
setSlot(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i, v);
}
inline js::Value *
JSObject::callObjVarArray()
{
JSFunction *fun = getCallObjCalleeFunction();
JS_ASSERT(hasContiguousSlots(JSObject::CALL_RESERVED_SLOTS + fun->nargs,
fun->script()->bindings.countVars()));
return getSlotAddress(JSObject::CALL_RESERVED_SLOTS + fun->nargs);
}
namespace js {
/*

View File

@ -120,7 +120,7 @@ Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
uint16 *indexp;
PropertyOp getter;
StrictPropertyOp setter;
uint32 slot = JSObject::CALL_RESERVED_SLOTS;
uint32 slot = CallObject::RESERVED_SLOTS;
if (kind == ARGUMENT) {
JS_ASSERT(nvars == 0);

View File

@ -93,6 +93,7 @@
#include "jsopcodeinlines.h"
#include "jstypedarrayinlines.h"
#include "vm/CallObject-inl.h"
#include "vm/Stack-inl.h"
#ifdef JS_METHODJIT
@ -3286,9 +3287,9 @@ public:
JS_ASSERT_IF(fp->hasArgsObj(), frameobj == &fp->argsObj());
fp->setArgsObj(*frameobj->asArguments());
if (frameobj->isNormalArguments())
frameobj->setPrivate(fp);
frameobj->asArguments()->setStackFrame(fp);
else
JS_ASSERT(!frameobj->getPrivate());
JS_ASSERT(!frameobj->asArguments()->maybeStackFrame());
debug_only_printf(LC_TMTracer,
"argsobj<%p> ",
(void *)frameobj);
@ -3301,12 +3302,12 @@ public:
} else {
JS_ASSERT(p == fp->addressOfScopeChain());
if (frameobj->isCall() &&
!frameobj->getPrivate() &&
fp->maybeCalleev().toObjectOrNull() == frameobj->getCallObjCallee())
!frameobj->asCall().maybeStackFrame() &&
fp->maybeCalleev().toObjectOrNull() == frameobj->asCall().getCallee())
{
JS_ASSERT(&fp->scopeChain() == StackFrame::sInvalidScopeChain);
frameobj->setPrivate(fp);
fp->setScopeChainWithOwnCallObj(*frameobj);
frameobj->asCall().setStackFrame(fp);
fp->setScopeChainWithOwnCallObj(frameobj->asCall());
} else {
fp->setScopeChainNoCallObj(*frameobj);
}
@ -3539,7 +3540,7 @@ GetFromClosure(JSContext* cx, JSObject* call, const ClosureVarInfo* cv, double*
// We already guarded on trace that we aren't touching an outer tree's entry frame
VOUCH_DOES_NOT_REQUIRE_STACK();
StackFrame* fp = (StackFrame*) call->getPrivate();
StackFrame* fp = call->asCall().maybeStackFrame();
JS_ASSERT(fp != cx->fp());
Value v;
@ -3577,12 +3578,12 @@ struct ArgClosureTraits
// Get the offset of our object slots from the object's slots pointer.
static inline uint32 slot_offset(JSObject* obj) {
return JSObject::CALL_RESERVED_SLOTS;
return CallObject::RESERVED_SLOTS;
}
// Get the maximum slot index of this type that should be allowed
static inline uint16 slot_count(JSObject* obj) {
return obj->getCallObjCalleeFunction()->nargs;
return obj->asCall().getCalleeFunction()->nargs;
}
private:
@ -3608,12 +3609,12 @@ struct VarClosureTraits
}
static inline uint32 slot_offset(JSObject* obj) {
return JSObject::CALL_RESERVED_SLOTS +
obj->getCallObjCalleeFunction()->nargs;
return CallObject::RESERVED_SLOTS +
obj->asCall().getCalleeFunction()->nargs;
}
static inline uint16 slot_count(JSObject* obj) {
return obj->getCallObjCalleeFunction()->script()->bindings.countVars();
return obj->asCall().getCalleeFunction()->script()->bindings.countVars();
}
private:
@ -8149,9 +8150,10 @@ TraceRecorder::entryFrameIns() const
* filled in with the depth of the call object's frame relevant to cx->fp().
*/
JS_REQUIRES_STACK StackFrame*
TraceRecorder::frameIfInRange(JSObject* obj, unsigned* depthp) const
TraceRecorder::frameIfInRange(JSObject *obj, unsigned* depthp) const
{
StackFrame* ofp = (StackFrame*) obj->getPrivate();
JS_ASSERT(obj->isCall() || obj->isArguments());
StackFrame* ofp = (StackFrame *) obj->getPrivate();
StackFrame* fp = cx->fp();
for (unsigned depth = 0; depth <= callDepth; ++depth) {
if (fp == ofp) {
@ -8264,7 +8266,8 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, const Value*&
uintN slot = uint16(shape->shortid);
vp = NULL;
StackFrame* cfp = (StackFrame*) obj->getPrivate();
CallObject &callobj = obj->asCall();
StackFrame* cfp = callobj.maybeStackFrame();
if (cfp) {
if (shape->getterOp() == GetCallArg) {
JS_ASSERT(slot < cfp->numFormalArgs());
@ -8281,7 +8284,7 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, const Value*&
// Now assert that our use of shape->shortid was in fact kosher.
JS_ASSERT(shape->hasShortID());
if (frameIfInRange(obj)) {
if (frameIfInRange(&callobj)) {
// At this point we are guaranteed to be looking at an active call oject
// whose properties are stored in the corresponding StackFrame.
ins = get(vp);
@ -12299,11 +12302,13 @@ TraceRecorder::setUpwardTrackedVar(Value* stackVp, const Value &v, LIns* v_ins)
}
JS_REQUIRES_STACK RecordingStatus
TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *shape,
TraceRecorder::setCallProp(JSObject *obj, LIns *callobj_ins, const Shape *shape,
LIns *v_ins, const Value &v)
{
CallObject &callobj = obj->asCall();
// Set variables in on-trace-stack call objects by updating the tracker.
StackFrame *fp = frameIfInRange(callobj);
StackFrame *fp = frameIfInRange(&callobj);
if (fp) {
if (shape->setterOp() == SetCallArg) {
JS_ASSERT(shape->hasShortID());
@ -12322,7 +12327,7 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *sh
RETURN_STOP("can't trace special CallClass setter");
}
if (!callobj->getPrivate()) {
if (!callobj.maybeStackFrame()) {
// Because the parent guard in guardCallee ensures this Call object
// will be the same object now and on trace, and because once a Call
// object loses its frame it never regains one, on trace we will also
@ -12330,11 +12335,11 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *sh
// write the value to the Call object's slot.
intN slot = uint16(shape->shortid);
if (shape->setterOp() == SetCallArg) {
JS_ASSERT(slot < ArgClosureTraits::slot_count(callobj));
slot += ArgClosureTraits::slot_offset(callobj);
JS_ASSERT(slot < ArgClosureTraits::slot_count(&callobj));
slot += ArgClosureTraits::slot_offset(obj);
} else if (shape->setterOp() == SetCallVar) {
JS_ASSERT(slot < VarClosureTraits::slot_count(callobj));
slot += VarClosureTraits::slot_offset(callobj);
JS_ASSERT(slot < VarClosureTraits::slot_count(&callobj));
slot += VarClosureTraits::slot_offset(obj);
} else {
RETURN_STOP("can't trace special CallClass setter");
}
@ -12345,7 +12350,7 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *sh
JS_ASSERT(shape->hasShortID());
LIns* slots_ins = NULL;
stobj_set_slot(callobj, callobj_ins, slot, slots_ins, v, v_ins);
stobj_set_slot(&callobj, callobj_ins, slot, slots_ins, v, v_ins);
return RECORD_CONTINUE;
}
@ -14997,7 +15002,7 @@ static inline bool
IsFindableCallObj(JSObject *obj)
{
return obj->isCall() &&
(obj->callIsForEval() || obj->getCallObjCalleeFunction()->isHeavyweight());
(obj->asCall().isForEval() || obj->asCall().getCalleeFunction()->isHeavyweight());
}
/*
@ -15134,8 +15139,7 @@ TraceRecorder::record_JSOP_BINDNAME()
* it. For now just don't trace this case.
*/
if (obj != globalObj) {
JS_ASSERT(obj->isCall());
JS_ASSERT(obj->callIsForEval());
JS_ASSERT(obj->asCall().isForEval());
RETURN_STOP_A("BINDNAME within strict eval code");
}

View File

@ -1272,7 +1272,7 @@ class TraceRecorder
JS_REQUIRES_STACK nanojit::LIns* scopeChain();
JS_REQUIRES_STACK nanojit::LIns* entryScopeChain() const;
JS_REQUIRES_STACK nanojit::LIns* entryFrameIns() const;
JS_REQUIRES_STACK StackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const;
JS_REQUIRES_STACK StackFrame* frameIfInRange(JSObject *obj, unsigned* depthp = NULL) const;
JS_REQUIRES_STACK RecordingStatus traverseScopeChain(JSObject *obj, nanojit::LIns *obj_ins, JSObject *obj2, nanojit::LIns *&obj2_ins);
JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, const Value*& vp, nanojit::LIns*& ins, NameResult& nr, JSObject **scopeObjp = NULL);
JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* shape, jsid id, const Value*& vp, nanojit::LIns*& ins, NameResult& nr);

View File

@ -54,6 +54,8 @@
#include "jsinterpinlines.h"
#include "jsautooplen.h"
#include "vm/CallObject-inl.h"
#if defined JS_POLYIC
using namespace js;
@ -421,7 +423,7 @@ class SetPropCompiler : public PICStubCompiler
// \\ V and getters, and
// \===/ 2. arguments and locals have different getters
// then we can rely on fun->nargs remaining invariant.
JSFunction *fun = obj->getCallObjCalleeFunction();
JSFunction *fun = obj->asCall().getCalleeFunction();
uint16 slot = uint16(shape->shortid);
/* Guard that the call object has a frame. */
@ -441,7 +443,7 @@ class SetPropCompiler : public PICStubCompiler
if (shape->setterOp() == SetCallVar)
slot += fun->nargs;
slot += JSObject::CALL_RESERVED_SLOTS;
slot += CallObject::RESERVED_SLOTS;
Address address = masm.objPropAddress(obj, pic.objReg, slot);
masm.storeValue(pic.u.vr, address);
@ -691,7 +693,7 @@ class SetPropCompiler : public PICStubCompiler
* objects may differ due to eval(), DEFFUN, etc.).
*/
RecompilationMonitor monitor(cx);
JSFunction *fun = obj->getCallObjCalleeFunction();
JSFunction *fun = obj->asCall().getCalleeFunction();
JSScript *script = fun->script();
uint16 slot = uint16(shape->shortid);
if (!script->ensureHasTypes(cx, fun))
@ -1504,7 +1506,7 @@ class ScopeNameCompiler : public PICStubCompiler
/* Get callobj's stack frame. */
masm.loadObjPrivate(pic.objReg, pic.shapeReg);
JSFunction *fun = getprop.holder->getCallObjCalleeFunction();
JSFunction *fun = getprop.holder->asCall().getCalleeFunction();
uint16 slot = uint16(shape->shortid);
Jump skipOver;
@ -1525,7 +1527,7 @@ class ScopeNameCompiler : public PICStubCompiler
if (kind == VAR)
slot += fun->nargs;
slot += JSObject::CALL_RESERVED_SLOTS;
slot += CallObject::RESERVED_SLOTS;
Address address = masm.objPropAddress(obj, pic.objReg, slot);
/* Safe because type is loaded first. */

View File

@ -482,7 +482,7 @@ stubs::GetElem(VMFrame &f)
if (arg < argsobj->initialLength()) {
copyFrom = &argsobj->element(arg);
if (!copyFrom->isMagic()) {
if (StackFrame *afp = (StackFrame *) argsobj->getPrivate())
if (StackFrame *afp = argsobj->maybeStackFrame())
copyFrom = &afp->canonicalActualArg(arg);
goto end_getelem;
}

View File

@ -110,6 +110,37 @@ ArgumentsObject::setElement(uint32 i, const js::Value &v)
data()->slots[i] = v;
}
inline js::StackFrame *
ArgumentsObject::maybeStackFrame() const
{
return reinterpret_cast<js::StackFrame *>(getPrivate());
}
inline void
ArgumentsObject::setStackFrame(StackFrame *frame)
{
return setPrivate(frame);
}
#define JS_ARGUMENTS_OBJECT_ON_TRACE ((void *)0xa126)
inline bool
ArgumentsObject::onTrace() const
{
return getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE;
}
inline void
ArgumentsObject::setOnTrace()
{
return setPrivate(JS_ARGUMENTS_OBJECT_ON_TRACE);
}
inline void
ArgumentsObject::clearOnTrace()
{
return setPrivate(NULL);
}
inline const js::Value &
NormalArgumentsObject::callee() const
{

View File

@ -47,8 +47,6 @@
class GetPropCompiler;
#endif
#define JS_ARGUMENTS_OBJECT_ON_TRACE ((void *)0xa126)
#ifdef JS_TRACER
namespace nanojit {
class ValidateWriter;
@ -229,6 +227,14 @@ class ArgumentsObject : public ::JSObject
inline const js::Value &element(uint32 i) const;
inline const js::Value *elements() const;
inline void setElement(uint32 i, const js::Value &v);
/* The stack frame for this ArgumentsObject, if the frame is still active. */
inline js::StackFrame *maybeStackFrame() const;
inline void setStackFrame(js::StackFrame *frame);
inline bool onTrace() const;
inline void setOnTrace();
inline void clearOnTrace();
};
/*

161
js/src/vm/CallObject-inl.h Normal file
View File

@ -0,0 +1,161 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=78:
*
* ***** 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 SpiderMonkey call object code.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Paul Biggar <pbiggar@mozilla.com> (original author)
*
* 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 CallObject_inl_h___
#define CallObject_inl_h___
#include "CallObject.h"
namespace js {
inline bool
CallObject::isForEval() const
{
JS_ASSERT(getFixedSlot(CALLEE_SLOT).isObjectOrNull());
JS_ASSERT_IF(getFixedSlot(CALLEE_SLOT).isObject(),
getFixedSlot(CALLEE_SLOT).toObject().isFunction());
return getFixedSlot(CALLEE_SLOT).isNull();
}
inline js::StackFrame *
CallObject::maybeStackFrame() const
{
return reinterpret_cast<js::StackFrame *>(getPrivate());
}
inline void
CallObject::setStackFrame(StackFrame *frame)
{
return setPrivate(frame);
}
inline void
CallObject::setCallee(JSObject *callee)
{
JS_ASSERT_IF(callee, callee->isFunction());
setFixedSlot(CALLEE_SLOT, js::ObjectOrNullValue(callee));
}
inline JSObject *
CallObject::getCallee() const
{
return getFixedSlot(CALLEE_SLOT).toObjectOrNull();
}
inline JSFunction *
CallObject::getCalleeFunction() const
{
return getFixedSlot(CALLEE_SLOT).toObject().getFunctionPrivate();
}
inline const js::Value &
CallObject::getArguments() const
{
JS_ASSERT(!isForEval());
return getFixedSlot(ARGUMENTS_SLOT);
}
inline void
CallObject::setArguments(const js::Value &v)
{
JS_ASSERT(!isForEval());
setFixedSlot(ARGUMENTS_SLOT, v);
}
inline const js::Value &
CallObject::arg(uintN i) const
{
JS_ASSERT(i < getCalleeFunction()->nargs);
return getSlot(RESERVED_SLOTS + i);
}
inline void
CallObject::setArg(uintN i, const js::Value &v)
{
JS_ASSERT(i < getCalleeFunction()->nargs);
setSlot(RESERVED_SLOTS + i, v);
}
inline const js::Value &
CallObject::var(uintN i) const
{
JSFunction *fun = getCalleeFunction();
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
JS_ASSERT(i < fun->script()->bindings.countVars());
return getSlot(RESERVED_SLOTS + fun->nargs + i);
}
inline void
CallObject::setVar(uintN i, const js::Value &v)
{
JSFunction *fun = getCalleeFunction();
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
JS_ASSERT(i < fun->script()->bindings.countVars());
setSlot(RESERVED_SLOTS + fun->nargs + i, v);
}
inline void
CallObject::copyValues(uintN nargs, Value *argv, uintN nvars, Value *slots)
{
JS_ASSERT(numSlots() >= RESERVED_SLOTS + nargs + nvars);
copySlotRange(RESERVED_SLOTS, argv, nargs);
copySlotRange(RESERVED_SLOTS + nargs, slots, nvars);
}
inline js::Value *
CallObject::argArray()
{
js::DebugOnly<JSFunction*> fun = getCalleeFunction();
JS_ASSERT(hasContiguousSlots(RESERVED_SLOTS, fun->nargs));
return getSlotAddress(RESERVED_SLOTS);
}
inline js::Value *
CallObject::varArray()
{
JSFunction *fun = getCalleeFunction();
JS_ASSERT(hasContiguousSlots(RESERVED_SLOTS + fun->nargs,
fun->script()->bindings.countVars()));
return getSlotAddress(RESERVED_SLOTS + fun->nargs);
}
}
#endif /* CallObject_inl_h___ */

100
js/src/vm/CallObject.cpp Normal file
View File

@ -0,0 +1,100 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=78:
*
* ***** 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 SpiderMonkey call object code.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Paul Biggar <pbiggar@mozilla.com> (original author)
*
* 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 "jsobjinlines.h"
#include "CallObject.h"
#include "CallObject-inl.h"
namespace js {
/*
* Construct a call object for the given bindings. If this is a call object
* for a function invocation, callee should be the function being called.
* Otherwise it must be a call object for eval of strict mode code, and callee
* must be null.
*/
CallObject *
CallObject::create(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee)
{
Bindings &bindings = script->bindings;
size_t argsVars = bindings.countArgsAndVars();
size_t slots = RESERVED_SLOTS + argsVars;
gc::AllocKind kind = gc::GetGCObjectKind(slots);
/*
* Make sure that the arguments and variables in the call object all end up
* in a contiguous range of slots. We need this to be able to embed the
* args/vars arrays in the TypeScriptNesting for the function, after the
* call object's frame has finished.
*/
if (cx->typeInferenceEnabled() && gc::GetGCKindSlots(kind) < slots) {
kind = gc::GetGCObjectKind(RESERVED_SLOTS);
JS_ASSERT(gc::GetGCKindSlots(kind) == RESERVED_SLOTS);
}
JSObject *obj = js_NewGCObject(cx, kind);
if (!obj)
return NULL;
/* Init immediately to avoid GC seeing a half-init'ed object. */
obj->initCall(cx, bindings, &scopeChain);
obj->makeVarObj();
/* This must come after callobj->lastProp has been set. */
if (!obj->ensureInstanceReservedSlots(cx, argsVars))
return NULL;
#ifdef DEBUG
for (Shape::Range r = obj->lastProp; !r.empty(); r.popFront()) {
const Shape &s = r.front();
if (s.slot != SHAPE_INVALID_SLOT) {
JS_ASSERT(s.slot + 1 == obj->slotSpan());
break;
}
}
#endif
CallObject &callobj = obj->asCall();
callobj.setCallee(callee);
return &callobj;
}
}

116
js/src/vm/CallObject.h Normal file
View File

@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=78:
*
* ***** 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 SpiderMonkey call object code.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Paul Biggar <pbiggar@mozilla.com> (original author)
*
* 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 CallObject_h___
#define CallObject_h___
namespace js {
class CallObject : public ::JSObject
{
/*
* Reserved slot structure for Call objects:
*
* private - the stack frame corresponding to the Call object
* until js_PutCallObject or its on-trace analog
* is called, null thereafter
* JSSLOT_CALL_CALLEE - callee function for the stack frame, or null if
* the stack frame is for strict mode eval code
* JSSLOT_CALL_ARGUMENTS - arguments object for non-strict mode eval stack
* frames (not valid for strict mode eval frames)
*/
static const uint32 CALLEE_SLOT = 0;
static const uint32 ARGUMENTS_SLOT = 1;
public:
/* Create a CallObject for the given callee function. */
static CallObject *
create(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee);
static const uint32 RESERVED_SLOTS = 2;
/* True if this is for a strict mode eval frame or for a function call. */
inline bool isForEval() const;
/* The stack frame for this CallObject, if the frame is still active. */
inline js::StackFrame *maybeStackFrame() const;
inline void setStackFrame(js::StackFrame *frame);
/*
* The callee function if this CallObject was created for a function
* invocation, or null if it was created for a strict mode eval frame.
*/
inline JSObject *getCallee() const;
inline JSFunction *getCalleeFunction() const;
inline void setCallee(JSObject *callee);
/* Returns the callee's arguments object. */
inline const js::Value &getArguments() const;
inline void setArguments(const js::Value &v);
/* Returns the formal argument at the given index. */
inline const js::Value &arg(uintN i) const;
inline void setArg(uintN i, const js::Value &v);
/* Returns the variable at the given index. */
inline const js::Value &var(uintN i) const;
inline void setVar(uintN i, const js::Value &v);
/*
* Get the actual arrays of arguments and variables. Only call if type
* inference is enabled, where we ensure that call object variables are in
* contiguous slots (see NewCallObject).
*/
inline js::Value *argArray();
inline js::Value *varArray();
inline void copyValues(uintN nargs, Value *argv, uintN nvars, Value *slots);
};
}
js::CallObject &
JSObject::asCall()
{
JS_ASSERT(isCall());
return *reinterpret_cast<js::CallObject *>(this);
}
#endif /* CallObject_h___ */

View File

@ -48,6 +48,8 @@
#include "jsscriptinlines.h"
#include "ArgumentsObject-inl.h"
#include "CallObject-inl.h"
#include "methodjit/MethodJIT.h"
namespace js {
@ -340,15 +342,15 @@ StackFrame::setScopeChainNoCallObj(JSObject &obj)
}
inline void
StackFrame::setScopeChainWithOwnCallObj(JSObject &obj)
StackFrame::setScopeChainWithOwnCallObj(CallObject &obj)
{
JS_ASSERT(&obj != NULL);
JS_ASSERT(!hasCallObj() && obj.isCall() && obj.getPrivate() == this);
JS_ASSERT(!hasCallObj() && obj.maybeStackFrame() == this);
scopeChain_ = &obj;
flags_ |= HAS_SCOPECHAIN | HAS_CALL_OBJ;
}
inline JSObject &
inline CallObject &
StackFrame::callObj() const
{
JS_ASSERT_IF(isNonEvalFunctionFrame() || isStrictEvalFrame(), hasCallObj());
@ -358,7 +360,7 @@ StackFrame::callObj() const
JS_ASSERT(IsCacheableNonGlobalScope(pobj) || pobj->isWith());
pobj = pobj->getParent();
}
return *pobj;
return pobj->asCall();
}
inline bool
@ -415,11 +417,11 @@ inline void
StackFrame::markFunctionEpilogueDone(bool activationOnly)
{
if (flags_ & (HAS_ARGS_OBJ | HAS_CALL_OBJ)) {
if (hasArgsObj() && !argsObj().getPrivate()) {
if (hasArgsObj() && !argsObj().maybeStackFrame()) {
args.nactual = args.obj->initialLength();
flags_ &= ~HAS_ARGS_OBJ;
}
if (hasCallObj() && !callObj().getPrivate()) {
if (hasCallObj() && !callObj().maybeStackFrame()) {
/*
* For function frames, the call object may or may not have have an
* enclosing DeclEnv object, so we use the callee's parent, since
@ -687,8 +689,7 @@ ArgumentsObject::getElement(uint32 i, Value *vp)
* If this arguments object was created on trace the actual argument value
* could be in a register or something, so we can't optimize.
*/
StackFrame *fp = reinterpret_cast<StackFrame *>(getPrivate());
if (fp == JS_ARGUMENTS_OBJECT_ON_TRACE)
if (onTrace())
return false;
/*
@ -696,6 +697,7 @@ ArgumentsObject::getElement(uint32 i, Value *vp)
* the canonical argument value. Note that strict arguments objects do not
* alias named arguments and never have a stack frame.
*/
StackFrame *fp = maybeStackFrame();
JS_ASSERT_IF(isStrictArguments(), !fp);
if (fp)
*vp = fp->canonicalActualArg(i);
@ -711,7 +713,7 @@ ArgumentsObject::getElements(uint32 start, uint32 count, Value *vp)
if (start > length || start + count > length)
return false;
StackFrame *fp = reinterpret_cast<StackFrame *>(getPrivate());
StackFrame *fp = maybeStackFrame();
/* If there's no stack frame for this, argument values are in elements(). */
if (!fp) {
@ -727,7 +729,7 @@ ArgumentsObject::getElements(uint32 start, uint32 count, Value *vp)
}
/* If we're on trace, there's no canonical location for elements: fail. */
if (fp == JS_ARGUMENTS_OBJECT_ON_TRACE)
if (onTrace())
return false;
/* Otherwise, element values are on the stack. */

View File

@ -159,9 +159,9 @@ StackFrame::stealFrameAndSlots(Value *vp, StackFrame *otherfp,
if (hasArgsObj()) {
ArgumentsObject &argsobj = argsObj();
if (argsobj.isNormalArguments())
argsobj.setPrivate(this);
argsobj.setStackFrame(this);
else
JS_ASSERT(!argsobj.getPrivate());
JS_ASSERT(!argsobj.maybeStackFrame());
otherfp->flags_ &= ~HAS_ARGS_OBJ;
}
}

View File

@ -851,9 +851,9 @@ class StackFrame
return ret;
}
inline JSObject &callObj() const;
inline CallObject &callObj() const;
inline void setScopeChainNoCallObj(JSObject &obj);
inline void setScopeChainWithOwnCallObj(JSObject &obj);
inline void setScopeChainWithOwnCallObj(CallObject &obj);
/*
* Prologue for function frames: make a call object for heavyweight

View File

@ -76,6 +76,7 @@ const AnimatedZoom = {
start: function start() {
this.tab = Browser.selectedTab;
this.browser = this.tab.browser;
this.bcr = this.browser.getBoundingClientRect();
this.zoomFrom = this.zoomRect || this.getStartRect();
this.startScale = this.browser.scale;
this.beginTime = mozAnimationStartTime;
@ -84,14 +85,13 @@ const AnimatedZoom = {
/** Get the visible rect, in device pixels relative to the content origin. */
getStartRect: function getStartRect() {
let browser = this.browser;
let bcr = browser.getBoundingClientRect();
let scroll = browser.getRootView().getPosition();
return new Rect(scroll.x, scroll.y, bcr.width, bcr.height);
return new Rect(scroll.x, scroll.y, this.bcr.width, this.bcr.height);
},
/** Update the visible rect, in device pixels relative to the content origin. */
updateTo: function(nextRect) {
let zoomRatio = window.innerWidth / nextRect.width;
let zoomRatio = this.bcr.width / nextRect.width;
let scale = this.startScale * zoomRatio;
let scrollX = nextRect.left * zoomRatio;
let scrollY = nextRect.top * zoomRatio;

View File

@ -161,15 +161,29 @@ let Util = {
return (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT);
},
isTablet: function isTablet() {
isTablet: function isTablet(options) {
let forceUpdate = options && 'forceUpdate' in options && options.forceUpdate;
if ('_isTablet' in this && !forceUpdate)
return this._isTablet;
let tabletPref = Services.prefs.getIntPref("browser.ui.layout.tablet");
// Act according to user prefs if tablet mode has been
// explicitly disabled or enabled.
if (tabletPref == 0)
return this._isTablet = false;
else if (tabletPref == 1)
return this._isTablet = true;
let dpi = this.displayDPI;
if (dpi <= 96)
return (window.innerWidth > 1024);
return this._isTablet = (window.innerWidth > 1024);
// See the tablet_panel_minwidth from mobile/themes/core/defines.inc
let tablet_panel_minwidth = 124;
let dpmm = 25.4 * window.innerWidth / dpi;
return (dpmm >= tablet_panel_minwidth);
return this._isTablet = (dpmm >= tablet_panel_minwidth);
},
isPortrait: function isPortrait() {

View File

@ -186,6 +186,8 @@ var BrowserUI = {
},
lockToolbar: function lockToolbar() {
if (Util.isTablet())
return;
this._toolbarLocked++;
document.getElementById("toolbar-moveable-container").top = "0";
if (this._toolbarLocked == 1)
@ -379,11 +381,6 @@ var BrowserUI = {
return this._toolbarH;
},
get sidebarW() {
delete this._sidebarW;
return this._sidebarW = Elements.controls.getBoundingClientRect().width;
},
sizeControls: function(windowW, windowH) {
// tabs
document.getElementById("tabs").resize();
@ -552,11 +549,27 @@ var BrowserUI = {
},
updateTabletLayout: function updateTabletLayout() {
let tabletPref = Services.prefs.getIntPref("browser.ui.layout.tablet");
if (tabletPref == 1 || (tabletPref == -1 && Util.isTablet()))
if (Util.isTablet({ forceUpdate: true })) {
this.unlockToolbar();
Elements.urlbarState.setAttribute("tablet", "true");
else
} else {
Elements.urlbarState.removeAttribute("tablet");
}
// Tablet mode changes the size of the thumbnails
// in the tabs container. Hence we have to force a
// thumbnail update on all tabs.
setTimeout(function(self) {
self._updateAllTabThumbnails();
}, 0, this);
},
_updateAllTabThumbnails: function() {
let tabs = Browser.tabs;
tabs.forEach(function(tab) {
tab.updateThumbnail({ force: true });
});
},
update: function(aState) {

View File

@ -1038,7 +1038,7 @@ var Browser = {
},
tryFloatToolbar: function tryFloatToolbar(dx, dy) {
if (this.floatedWhileDragging)
if (this.floatedWhileDragging || Util.isTablet())
return;
let [leftvis, ritevis, leftw, ritew] = Browser.computeSidebarVisibility(dx, dy);
@ -1289,7 +1289,7 @@ Browser.MainDragger.prototype = {
let bcr = browser.getBoundingClientRect();
this._contentView = browser.getViewAt(clientX - bcr.left, clientY - bcr.top);
this._stopAtSidebar = 0;
this._panToolbars = !Elements.urlbarState.getAttribute("tablet");
this._panToolbars = !Util.isTablet();
if (this._sidebarTimeout) {
clearTimeout(this._sidebarTimeout);
this._sidebarTimeout = null;
@ -1908,7 +1908,7 @@ const ContentTouchHandler = {
// or if the urlbar is showing
this.canCancelPan = (aX >= rect.left + kSafetyX) && (aX <= rect.right - kSafetyX) &&
(aY >= rect.top + kSafetyY) &&
(bcr.top == 0 || Elements.urlbarState.getAttribute("tablet"));
(bcr.top == 0 || Util.isTablet());
},
tapDown: function tapDown(aX, aY) {
@ -2899,7 +2899,6 @@ Tab.prototype = {
let notification = this._notification = document.createElement("notificationbox");
notification.classList.add("inputHandler");
// Create the browser using the current width the dynamically size the height
let browser = this._browser = document.createElement("browser");
browser.setAttribute("class", "viewable-width viewable-height");
this._chromeTab.linkedBrowser = browser;
@ -3155,15 +3154,18 @@ function rendererFactory(aBrowser, aCanvas) {
*/
var ViewableAreaObserver = {
get width() {
return this._width || window.innerWidth;
let width = this._width || window.innerWidth;
if (Util.isTablet()) {
let sidebarWidth = Math.round(Elements.tabs.getBoundingClientRect().width);
width -= sidebarWidth;
}
return width;
},
get height() {
let height = (this._height || window.innerHeight);
if (Elements.urlbarState.getAttribute("tablet")) {
let toolbarHeight = Math.round(document.getElementById("toolbar-main").getBoundingClientRect().height);
height -= toolbarHeight;
}
if (Util.isTablet())
height -= BrowserUI.toolbarH;
return height;
},

View File

@ -198,22 +198,22 @@
<stack flex="1" id="stack">
<scrollbox id="controls-scrollbox" style="overflow: hidden; -moz-box-orient: horizontal; position: relative;" flex="1" observes="bcast_urlbarState">
<vbox id="tabs-sidebar" class="sidebar" observes="bcast_uidiscovery">
<spacer class="toolbar-height"/>
<spacer class="toolbar-height" id="tabs-spacer" observes="bcast_urlbarState"/>
<!-- Left toolbar -->
<vbox id="tabs-container" class="panel-dark" flex="1">
<vbox id="tabs" flex="1"
<vbox id="tabs-container" class="panel-dark" flex="1" observes="bcast_urlbarState">
<vbox id="tabs" flex="1" observes="bcast_urlbarState"
onselect="BrowserUI.selectTab(this);"
onreloadtab="BrowserUI.undoCloseTab()"
onclosetab="BrowserUI.closeTab(this)"
onclosereloadtab="this._container.removeTab(this)"/>
<hbox id="tabs-controls">
<toolbarbutton id="newtab-button" class="button-control" command="cmd_newTab"/>
<toolbarbutton id="newtab-button" class="button-control" command="cmd_newTab" observes="bcast_urlbarState"/>
</hbox>
</vbox>
</vbox>
<!-- Page Area -->
<stack>
<stack id="page-stack" observes="bcast_urlbarState">
<scrollbox id="page-scrollbox">
<vbox>
<!-- Main Toolbar -->

View File

@ -1209,6 +1209,7 @@ GestureModule.prototype = {
let delta = 0;
let browser = AnimatedZoom.browser;
let oldScale = browser.scale;
let bcr = this._browserBCR;
// Accumulate pinch delta. Small changes are just jitter.
this._pinchDelta += aEvent.delta;
@ -1223,13 +1224,13 @@ GestureModule.prototype = {
let newScale = Browser.selectedTab.clampZoomLevel(oldScale * (1 + delta / this._scalingFactor));
let startScale = AnimatedZoom.startScale;
let scaleRatio = startScale / newScale;
let cX = aEvent.clientX - this._browserBCR.left;
let cY = aEvent.clientY - this._browserBCR.top;
let cX = aEvent.clientX - bcr.left;
let cY = aEvent.clientY - bcr.top;
// Calculate the new zoom rect.
let rect = AnimatedZoom.zoomFrom.clone();
rect.translate(this._pinchStartX - cX + (1-scaleRatio) * cX * rect.width / window.innerWidth,
this._pinchStartY - cY + (1-scaleRatio) * cY * rect.height / window.innerHeight);
rect.translate(this._pinchStartX - cX + (1-scaleRatio) * cX * rect.width / bcr.width,
this._pinchStartY - cY + (1-scaleRatio) * cY * rect.height / bcr.height);
rect.width *= scaleRatio;
rect.height *= scaleRatio;

View File

@ -7,21 +7,61 @@
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="documenttab">
<content>
<content observes="bcast_urlbarState">
<xul:stack anonid="page" class="documenttab-container" flex="1">
<html:canvas anonid="thumbnail" class="documenttab-thumbnail" left="0" width="104" height="65" moz-opaque="true" empty="true"
onclick="document.getBindingParent(this)._onClick()"/>
<xul:hbox class="documenttab-reload" left="0" top="0" width="104" height="65" onclick="document.getBindingParent(this)._onUndo();"/>
<xul:hbox class="documenttab-close-container" start="-16" top="0" height="65" width="55" align="center" onclick="document.getBindingParent(this)._onClose()">
<xul:image anonid="close" class="documenttab-close" mousethrough="always"/>
<html:canvas anonid="thumbnail" class="documenttab-thumbnail" left="0" moz-opaque="true" empty="true"
onclick="document.getBindingParent(this)._onClick()" observes="bcast_urlbarState"/>
<xul:hbox anonid="reload" class="documenttab-reload" left="0" top="0" onclick="document.getBindingParent(this)._onUndo();" observes="bcast_urlbarState"/>
<xul:hbox anonid="close-container" class="documenttab-close-container" top="0" align="center" onclick="document.getBindingParent(this)._onClose()" observes="bcast_urlbarState">
<xul:image anonid="close" class="documenttab-close" mousethrough="always" observes="bcast_urlbarState"/>
</xul:hbox>
</xul:stack>
</content>
<implementation>
<field name="ignoreUndo">false</field>
<field name="thumbnail">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail");</field>
<field name="_container">this.parentNode.parentNode;</field>
<field name="thumbnail" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail");</field>
<field name="_reload" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "reload");</field>
<field name="_closeContainer" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "close-container");</field>
<field name="_container" readonly="true">this.parentNode.parentNode;</field>
<constructor>
<![CDATA[
this.updateTabletLayout(this.thumbnail);
]]>
</constructor>
<method name="updateTabletLayout">
<parameter name="thumbnail"/>
<body>
<![CDATA[
let tabWidth, tabHeight, closeWidth, closeHeight;
if (Util.isTablet()) {
tabWidth = 176;
tabHeight = 110;
closeWidth = 41;
closeHeight = 117;
} else {
tabWidth = 104;
tabHeight = 65;
closeWidth = 55;
closeHeight = 65;
}
if (tabWidth != thumbnail.width) {
let reload = this._reload;
let closeContainer = this._closeContainer;
thumbnail.width = reload.width = tabWidth;
thumbnail.height = reload.height = tabHeight;
closeContainer.width = closeWidth;
closeContainer.height = closeHeight;
}
]]>
</body>
</method>
<method name="_onClick">
<body>
<![CDATA[
@ -61,14 +101,18 @@
<body>
<![CDATA[
let thumbnail = this.thumbnail;
// Ensure the thumbnail will have the correct
// dimensions for tablet and phone modes
this.updateTabletLayout(thumbnail);
if (browser.currentURI.spec == "about:blank") {
thumbnail.setAttribute("empty", "true");
return;
}
thumbnail.removeAttribute("empty");
const tabWidth = 104;
const tabHeight = 65;
const tabWidth = thumbnail.width;
const tabHeight = thumbnail.height;
let ratio = tabHeight / tabWidth;
if (browser.contentDocumentWidth > 0)
@ -118,7 +162,7 @@
<binding id="tablist">
<content>
<xul:scrollbox anonid="tabs-scrollbox" flex="1">
<xul:scrollbox anonid="tabs-scrollbox" class="tabs-scrollbox" flex="1">
<xul:vbox class="tabs-list" anonid="tabs-children" />
</xul:scrollbox>
<xul:box class="tabs-list" anonid="tabs-undo"/>
@ -241,7 +285,7 @@
// We can't rely on getBoundingClientRect() for this.children height
// it is not synced (sometimes, especially during resize) with the
// style.height rule
let columnsCount = Math.ceil(this.children.childNodes.length / Math.floor(parseInt(this.children.style.height) / (firstBox.height + 4)));
let columnsCount = Util.isTablet() ? 1 : Math.ceil(this.children.childNodes.length / Math.floor(parseInt(this.children.style.height) / (firstBox.height + 4)));
if (this._columnsCount != columnsCount && window.innerWidth > 1) { // > 1 to ignore column resizing while the main window is loading
let width = columnsCount * (COLUMN_MARGIN + firstBox.width);
this.children.style.width = width + "px";

View File

@ -929,7 +929,7 @@ autocompleteresult.noresults > .autocomplete-item-container {
-moz-box-align: start;
}
#tabs > scrollbox {
#tabs > .tabs-scrollbox {
max-width: 350px;
}
@ -986,6 +986,7 @@ documenttab[selected="true"] > stack > .documenttab-thumbnail {
.documenttab-close-container {
position: relative;
left: -16px;
-moz-margin-start: -16px;
-moz-margin-end: 49px;
}
@ -1575,46 +1576,6 @@ setting {
to { -moz-transform: translateX(0); }
}
/* Tablet mode */
.spacer-actionbar,
.button-actionbar {
visibility: collapse;
}
.button-actionbar[disabled="true"] {
opacity: 0.5;
}
.button-actionbar:hover:active {
background-color: #8db8d8;
}
#toolbar-main[tablet="true"] > .spacer-actionbar,
#toolbar-main[tablet="true"] > .button-actionbar {
visibility: visible;
}
#controls-scrollbox[tablet="true"] > #controls-sidebar {
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar {
border: none;
position: fixed;
top: -moz-calc(@touch_button_xlarge@ + @margin_normal@);
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(ltr) {
right: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(rtl) {
left: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar[open] {
visibility: visible;
}
/* Text selection handles */
#selectionhandle-start,
@ -1640,4 +1601,6 @@ setting {
#search-engines-popup {
max-width: -moz-calc(@tablet_panel_minwidth@);
}
}
}
%include tablet.css

View File

@ -879,7 +879,7 @@ autocompleteresult.noresults > .autocomplete-item-container {
-moz-box-align: start;
}
#tabs > scrollbox {
#tabs > .tabs-scrollbox {
max-width: 350px;
}
@ -935,6 +935,7 @@ documenttab[selected="true"] > stack > .documenttab-thumbnail {
.documenttab-close-container {
position: relative;
left: -16px;
-moz-margin-start: -16px;
-moz-margin-end: 49px;
}
@ -1545,46 +1546,6 @@ setting {
to { -moz-transform: translateX(0); }
}
/* Tablet mode */
.spacer-actionbar,
.button-actionbar {
visibility: collapse;
}
.button-actionbar[disabled="true"] {
opacity: 0.5;
}
.button-actionbar:hover:active {
background-color: #8db8d8;
}
#toolbar-main[tablet="true"] > .spacer-actionbar,
#toolbar-main[tablet="true"] > .button-actionbar {
visibility: visible;
}
#controls-scrollbox[tablet="true"] > #controls-sidebar {
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar {
border: none;
position: fixed;
top: -moz-calc(@touch_button_xlarge@ + @margin_normal@);
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(ltr) {
right: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(rtl) {
left: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar[open] {
visibility: visible;
}
/* Text selection handles */
#selectionhandle-start,
@ -1603,11 +1564,4 @@ setting {
list-style-image: url("chrome://browser/skin/images/handle-end.png");
}
@media (min-width: @tablet_panel_minwidth@) {
#awesome-panels {
-moz-box-shadow: 0px 0px @shadow_width_small@ black;
}
#search-engines-popup {
max-width: -moz-calc(@tablet_panel_minwidth@);
}
}
%include ../tablet.css

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -37,6 +37,7 @@
%filter substitution
%include defines.inc
%define honeycomb 1
/* main toolbar (URL bar) -------------------------------------------------- */
#toolbar-main {
@ -962,7 +963,7 @@ autocompleteresult.noresults > .autocomplete-item-container {
-moz-box-align: start;
}
#tabs > scrollbox {
#tabs > .tabs-scrollbox {
max-width: 350px;
}
@ -1018,6 +1019,7 @@ documenttab[selected="true"] > stack > .documenttab-thumbnail {
.documenttab-close-container {
position: relative;
left: -16px;
-moz-margin-start: -16px;
-moz-margin-end: 49px;
}
@ -1694,42 +1696,6 @@ setting {
to { -moz-transform: translateX(0); }
}
/* Tablet mode */
.spacer-actionbar,
.button-actionbar {
visibility: collapse;
}
.button-actionbar[disabled="true"] {
opacity: 0.5;
}
#toolbar-main[tablet="true"] > .spacer-actionbar,
#toolbar-main[tablet="true"] > .button-actionbar {
visibility: visible;
}
#controls-scrollbox[tablet="true"] > #controls-sidebar {
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar {
border: none;
position: fixed;
top: @touch_button_xlarge@;
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(ltr) {
left: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(rtl) {
right: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar[open] {
visibility: visible;
}
/* Text selection handles */
#selectionhandle-start,
@ -1814,3 +1780,5 @@ setting {
}
}
%include ../tablet.css

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 940 B

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -90,10 +90,12 @@ chrome.jar:
skin/images/row-header-bg.png (images/row-header-bg.png)
skin/images/console-default-hdpi.png (images/console-default-hdpi.png)
skin/images/newtab-default-hdpi.png (images/newtab-default-hdpi.png)
skin/images/newtab-default-tablet-hdpi.png (images/newtab-default-tablet-hdpi.png)
skin/images/tab-active-hdpi.png (images/tab-active-hdpi.png)
skin/images/tab-inactive-hdpi.png (images/tab-inactive-hdpi.png)
skin/images/tab-closed-hdpi.png (images/tab-closed-hdpi.png)
skin/images/tab-reopen-hdpi.png (images/tab-reopen-hdpi.png)
skin/images/tab-reopen-tablet-hdpi.png (images/tab-reopen-tablet-hdpi.png)
skin/images/remotetabs-48.png (images/remotetabs-48.png)
skin/images/remotetabs-32.png (images/remotetabs-32.png)
skin/images/mozilla-32.png (images/mozilla-32.png)
@ -110,8 +112,12 @@ chrome.jar:
skin/images/unlocked-hdpi.png (images/unlocked-hdpi.png)
skin/images/locked-hdpi.png (images/locked-hdpi.png)
skin/images/close-default-hdpi.png (images/close-default-hdpi.png)
skin/images/close-default-tablet-hdpi.png (images/close-default-tablet-hdpi.png)
skin/images/close-active-hdpi.png (images/close-active-hdpi.png)
skin/images/close-active-tablet-hdpi.png (images/close-active-tablet-hdpi.png)
skin/images/close-inactive-tab-hdpi.png (images/close-inactive-tab-hdpi.png)
skin/images/close-inactive-tab-tablet-hdpi.png (images/close-inactive-tab-tablet-hdpi.png)
skin/images/close-background-hdpi.png (images/close-background-hdpi.png)
skin/images/check-30.png (images/check-30.png)
skin/images/search-glass-30.png (images/search-glass-30.png)
skin/images/search-clear-30.png (images/search-clear-30.png)
@ -214,10 +220,12 @@ chrome.jar:
skin/gingerbread/images/row-header-bg.png (gingerbread/images/row-header-bg.png)
skin/gingerbread/images/console-default-hdpi.png (gingerbread/images/console-default-hdpi.png)
skin/gingerbread/images/newtab-default-hdpi.png (gingerbread/images/newtab-default-hdpi.png)
skin/gingerbread/images/newtab-default-tablet-hdpi.png (gingerbread/images/newtab-default-tablet-hdpi.png)
skin/gingerbread/images/tab-active-hdpi.png (gingerbread/images/tab-active-hdpi.png)
skin/gingerbread/images/tab-inactive-hdpi.png (gingerbread/images/tab-inactive-hdpi.png)
skin/gingerbread/images/tab-closed-hdpi.png (gingerbread/images/tab-closed-hdpi.png)
skin/gingerbread/images/tab-reopen-hdpi.png (gingerbread/images/tab-reopen-hdpi.png)
skin/gingerbread/images/tab-reopen-tablet-hdpi.png (gingerbread/images/tab-reopen-tablet-hdpi.png)
skin/gingerbread/images/remotetabs-48.png (gingerbread/images/remotetabs-48.png)
skin/gingerbread/images/remotetabs-32.png (gingerbread/images/remotetabs-32.png)
skin/gingerbread/images/mozilla-32.png (images/mozilla-32.png)
@ -233,8 +241,12 @@ chrome.jar:
skin/gingerbread/images/unlocked-hdpi.png (gingerbread/images/unlocked-hdpi.png)
skin/gingerbread/images/locked-hdpi.png (gingerbread/images/locked-hdpi.png)
skin/gingerbread/images/close-default-hdpi.png (gingerbread/images/close-default-hdpi.png)
skin/gingerbread/images/close-default-tablet-hdpi.png (gingerbread/images/close-default-tablet-hdpi.png)
skin/gingerbread/images/close-active-hdpi.png (gingerbread/images/close-active-hdpi.png)
skin/gingerbread/images/close-active-tablet-hdpi.png (gingerbread/images/close-active-tablet-hdpi.png)
skin/gingerbread/images/close-background-hdpi.png (gingerbread/images/close-background-hdpi.png)
skin/gingerbread/images/close-inactive-tab-hdpi.png (gingerbread/images/close-inactive-tab-hdpi.png)
skin/gingerbread/images/close-inactive-tab-tablet-hdpi.png (gingerbread/images/close-inactive-tab-tablet-hdpi.png)
skin/gingerbread/images/check-30.png (gingerbread/images/check-30.png)
skin/gingerbread/images/search-glass-30.png (gingerbread/images/search-glass-30.png)
skin/gingerbread/images/search-clear-30.png (gingerbread/images/search-clear-30.png)
@ -339,10 +351,12 @@ chrome.jar:
skin/honeycomb/images/row-header-bg.png (honeycomb/images/row-header-bg.png)
skin/honeycomb/images/console-default-hdpi.png (honeycomb/images/console-default-hdpi.png)
skin/honeycomb/images/newtab-default-hdpi.png (honeycomb/images/newtab-default-hdpi.png)
skin/honeycomb/images/newtab-default-tablet-hdpi.png (honeycomb/images/newtab-default-tablet-hdpi.png)
skin/honeycomb/images/tab-active-hdpi.png (honeycomb/images/tab-active-hdpi.png)
skin/honeycomb/images/tab-inactive-hdpi.png (honeycomb/images/tab-inactive-hdpi.png)
skin/honeycomb/images/tab-closed-hdpi.png (honeycomb/images/tab-closed-hdpi.png)
skin/honeycomb/images/tab-reopen-hdpi.png (honeycomb/images/tab-reopen-hdpi.png)
skin/honeycomb/images/tab-reopen-tablet-hdpi.png (honeycomb/images/tab-reopen-tablet-hdpi.png)
skin/honeycomb/images/remotetabs-48.png (honeycomb/images/remotetabs-48.png)
skin/honeycomb/images/remotetabs-32.png (honeycomb/images/remotetabs-32.png)
skin/honeycomb/images/mozilla-32.png (images/mozilla-32.png)
@ -359,8 +373,12 @@ chrome.jar:
skin/honeycomb/images/unlocked-hdpi.png (honeycomb/images/unlocked-hdpi.png)
skin/honeycomb/images/locked-hdpi.png (honeycomb/images/locked-hdpi.png)
skin/honeycomb/images/close-default-hdpi.png (honeycomb/images/close-default-hdpi.png)
skin/honeycomb/images/close-default-tablet-hdpi.png (honeycomb/images/close-default-tablet-hdpi.png)
skin/honeycomb/images/close-active-hdpi.png (honeycomb/images/close-active-hdpi.png)
skin/honeycomb/images/close-active-tablet-hdpi.png (honeycomb/images/close-active-tablet-hdpi.png)
skin/honeycomb/images/close-background-hdpi.png (honeycomb/images/close-background-hdpi.png)
skin/honeycomb/images/close-inactive-tab-hdpi.png (honeycomb/images/close-inactive-tab-hdpi.png)
skin/honeycomb/images/close-inactive-tab-tablet-hdpi.png (honeycomb/images/close-inactive-tab-tablet-hdpi.png)
skin/honeycomb/images/check-30.png (images/check-30.png)
skin/honeycomb/images/check-selected-hdpi.png (honeycomb/images/check-selected-hdpi.png)
skin/honeycomb/images/check-unselected-hdpi.png (honeycomb/images/check-unselected-hdpi.png)

View File

@ -0,0 +1,144 @@
.spacer-actionbar,
.button-actionbar {
visibility: collapse;
}
.button-actionbar[disabled="true"] {
opacity: 0.5;
}
%ifndef honeycomb
.button-actionbar:hover:active {
background-color: #8db8d8;
}
%endif
#toolbar-main[tablet="true"] > .spacer-actionbar,
#toolbar-main[tablet="true"] > .button-actionbar {
visibility: visible;
}
#toolbar-main[tablet="true"] > #tool-tabs {
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #controls-sidebar {
visibility: collapse;
}
#tabs-spacer[tablet="true"] {
visibility: collapse;
}
#tabs-container[tablet="true"] {
-moz-border-end: 0px;
background: #000;
}
#tabs[tablet="true"] > .tabs-scrollbox {
max-width: 200px;
-moz-box-orient: vertical;
}
#tabs[tablet="true"] .tabs-list {
}
#tabs[tablet="true"] .tabs-list {
width: 200px;
-moz-column-width: auto;
-moz-padding-end: 0px;
-moz-padding-start: 0px;
}
documenttab[tablet="true"] {
/* Use px instead of mozmm because tab bar items have hard-coded pixel sizes */
width: 200px;
padding: 12px;
-moz-margin-start: 0px;
background: none;
}
documenttab[tablet="true"][selected="true"] {
background: none;
}
.documenttab-thumbnail[tablet="true"] {
border-radius: @border_radius_tiny@;
}
.documenttab-close-container[tablet="true"] {
left: 0px;
-moz-margin-end: 0px;
-moz-margin-start: 135px;
-moz-box-pack: end;
-moz-box-align: center;
}
documenttab[selected="true"] > stack > .documenttab-close-container[tablet="true"] {
background: url("chrome://browser/skin/images/close-background-hdpi.png");
background-repeat: no-repeat;
background-position: right;
-moz-margin-end: -12px;
padding-right: 2px;
}
.documenttab-close[tablet="true"] {
width: 30px;
height: 44px;
list-style-image: url("chrome://browser/skin/images/close-inactive-tab-tablet-hdpi.png");
}
documenttab[selected="true"] > stack > hbox > .documenttab-close[tablet="true"] {
list-style-image: url("chrome://browser/skin/images/close-default-tablet-hdpi.png");
}
.documenttab-close-container:hover:active > .documenttab-close[tablet="true"] {
list-style-image: url("chrome://browser/skin/images/close-active-tablet-hdpi.png");
}
.documenttab-reload[tablet="true"] {
background: url("chrome://browser/skin/images/tab-reopen-tablet-hdpi.png");
}
#newtab-button[tablet="true"] {
list-style-image: url("images/newtab-default-tablet-hdpi.png");
}
@media (@orientation@: portrait) {
#toolbar-main[tablet="true"] > #tool-tabs {
visibility: visible;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar {
border: none;
%ifdef honeycomb
top: @touch_button_xlarge@;
%else
top: -moz-calc(@touch_button_xlarge@ + @margin_normal@);
%endif
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(ltr) {
left: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(rtl) {
right: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar[open] {
position: fixed;
visibility: visible;
}
}
%ifndef honeycomb
@media (min-width: @tablet_panel_minwidth@) {
#awesome-panels {
-moz-box-shadow: 0px 0px @shadow_width_small@ black;
}
#search-engines-popup {
max-width: -moz-calc(@tablet_panel_minwidth@);
}
}
%endif

View File

@ -78,6 +78,7 @@ LOCAL_INCLUDES += \
LOCAL_INCLUDES += -I$(topsrcdir)/layout/svg/base/src
include $(topsrcdir)/config/rules.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
# Because imgFrame.cpp includes "cairo.h"
CXXFLAGS += $(MOZ_CAIRO_CFLAGS)

View File

@ -42,6 +42,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "base/histogram.h"
#include "nsComponentManagerUtils.h"
#include "imgIContainerObserver.h"
#include "ImageErrors.h"
@ -191,6 +192,7 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
mDecoder(nsnull),
mWorker(nsnull),
mBytesDecoded(0),
mDecodeCount(0),
#ifdef DEBUG
mFramesNotified(0),
#endif
@ -208,6 +210,7 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
// Set up the discard tracker node.
mDiscardTrackerNode.curr = this;
mDiscardTrackerNode.prev = mDiscardTrackerNode.next = nsnull;
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0);
// Statistics
num_containers++;
@ -2197,6 +2200,12 @@ RasterImage::InitDecoder(bool aDoSizeDecode)
// Create a decode worker
mWorker = new imgDecodeWorker(this);
if (!aDoSizeDecode) {
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Subtract(mDecodeCount);
mDecodeCount++;
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(mDecodeCount);
}
CONTAINER_ENSURE_TRUE(mWorker, NS_ERROR_OUT_OF_MEMORY);
return NS_OK;

View File

@ -503,6 +503,10 @@ private: // data
nsRefPtr<imgDecodeWorker> mWorker;
PRUint32 mBytesDecoded;
// How many times we've decoded this image.
// This is currently only used for statistics
PRInt32 mDecodeCount;
#ifdef DEBUG
PRUint32 mFramesNotified;
#endif

View File

@ -234,7 +234,7 @@ nsIOService::Init()
if (observerService) {
observerService->AddObserver(this, kProfileChangeNetTeardownTopic, PR_TRUE);
observerService->AddObserver(this, kProfileChangeNetRestoreTopic, PR_TRUE);
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
observerService->AddObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, PR_TRUE);
observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, PR_TRUE);
}
else
@ -969,7 +969,7 @@ nsIOService::Observe(nsISupports *subject,
}
}
}
else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
else if (!strcmp(topic, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID)) {
// Remember we passed XPCOM shutdown notification to prevent any
// changes of the offline status from now. We must not allow going
// online after this point.

View File

@ -81,6 +81,9 @@
#define NS_PARENTALCONTROLSSERVICE_CONTRACTID \
"@mozilla.org/parental-controls-service;1"
#define NS_URLCLASSIFIERPREFIXSET_CONTRACTID \
"@mozilla.org/url-classifier/prefixset;1"
#define NS_URLCLASSIFIERDBSERVICE_CONTRACTID \
"@mozilla.org/url-classifier/dbservice;1"
@ -156,7 +159,11 @@
// {e7f70966-9a37-48d7-8aeb-35998f31090e}
#define NS_TYPEAHEADFIND_CID \
{ 0xe7f70966, 0x9a37, 0x48d7, { 0x8a, 0xeb, 0x35, 0x99, 0x8f, 0x31, 0x09, 0x0e} }
// {42ef1d52-3351-4973-98f8-d18f089bccfa}
#define NS_URLCLASSIFIERPREFIXSET_CID \
{ 0x42ef1d52, 0x3351, 0x4973, { 0x98, 0xf8, 0xd1, 0x8f, 0x08, 0x9b, 0xcc, 0xfa} }
// {5eb7c3c1-ec1f-4007-87cc-eefb37d68ce6}
#define NS_URLCLASSIFIERDBSERVICE_CID \
{ 0x5eb7c3c1, 0xec1f, 0x4007, { 0x87, 0xcc, 0xee, 0xfb, 0x37, 0xd6, 0x8c, 0xe6} }

View File

@ -63,6 +63,7 @@
#include "nsUrlClassifierDBService.h"
#include "nsUrlClassifierStreamUpdater.h"
#include "nsUrlClassifierUtils.h"
#include "nsUrlClassifierPrefixSet.h"
#endif
#ifdef MOZ_FEEDS
@ -94,6 +95,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDownloadProxy)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTypeAheadFind)
#ifdef MOZ_URL_CLASSIFIER
NS_GENERIC_FACTORY_CONSTRUCTOR(nsUrlClassifierPrefixSet)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsUrlClassifierStreamUpdater)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsUrlClassifierUtils, Init)
@ -138,6 +140,7 @@ NS_DEFINE_NAMED_CID(NS_DOWNLOAD_CID);
NS_DEFINE_NAMED_CID(NS_FIND_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_TYPEAHEADFIND_CID);
#ifdef MOZ_URL_CLASSIFIER
NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERPREFIXSET_CID);
NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERDBSERVICE_CID);
NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERSTREAMUPDATER_CID);
NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERUTILS_CID);
@ -164,6 +167,7 @@ static const mozilla::Module::CIDEntry kToolkitCIDs[] = {
{ &kNS_FIND_SERVICE_CID, false, NULL, nsFindServiceConstructor },
{ &kNS_TYPEAHEADFIND_CID, false, NULL, nsTypeAheadFindConstructor },
#ifdef MOZ_URL_CLASSIFIER
{ &kNS_URLCLASSIFIERPREFIXSET_CID, false, NULL, nsUrlClassifierPrefixSetConstructor },
{ &kNS_URLCLASSIFIERDBSERVICE_CID, false, NULL, nsUrlClassifierDBServiceConstructor },
{ &kNS_URLCLASSIFIERSTREAMUPDATER_CID, false, NULL, nsUrlClassifierStreamUpdaterConstructor },
{ &kNS_URLCLASSIFIERUTILS_CID, false, NULL, nsUrlClassifierUtilsConstructor },
@ -192,6 +196,7 @@ static const mozilla::Module::ContractIDEntry kToolkitContracts[] = {
{ NS_FIND_SERVICE_CONTRACTID, &kNS_FIND_SERVICE_CID },
{ NS_TYPEAHEADFIND_CONTRACTID, &kNS_TYPEAHEADFIND_CID },
#ifdef MOZ_URL_CLASSIFIER
{ NS_URLCLASSIFIERPREFIXSET_CONTRACTID, &kNS_URLCLASSIFIERPREFIXSET_CID },
{ NS_URLCLASSIFIERDBSERVICE_CONTRACTID, &kNS_URLCLASSIFIERDBSERVICE_CID },
{ NS_URICLASSIFIERSERVICE_CONTRACTID, &kNS_URLCLASSIFIERDBSERVICE_CID },
{ NS_URLCLASSIFIERSTREAMUPDATER_CONTRACTID, &kNS_URLCLASSIFIERSTREAMUPDATER_CID },

View File

@ -149,7 +149,7 @@ GetHistogramByEnumId(Telemetry::ID id, Histogram **ret)
const TelemetryHistogram &p = gHistograms[id];
nsresult rv = HistogramGet(p.id, p.min, p.max, p.bucketCount, p.histogramType, &h);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
return rv;
*ret = knownHistograms[id] = h;
return NS_OK;
@ -411,6 +411,14 @@ Accumulate(ID aHistogram, PRUint32 aSample)
h->Add(aSample);
}
base::Histogram*
GetHistogramById(ID id)
{
Histogram *h = NULL;
GetHistogramByEnumId(id, &h);
return h;
}
} // namespace Telemetry
} // namespace mozilla

View File

@ -42,6 +42,10 @@
#include "mozilla/TimeStamp.h"
#include "mozilla/AutoRestore.h"
namespace base {
class Histogram;
}
namespace mozilla {
namespace Telemetry {
@ -62,6 +66,11 @@ HistogramCount
*/
void Accumulate(ID id, PRUint32 sample);
/**
* Return a raw Histogram for direct manipulation for users who can not use Accumulate().
*/
base::Histogram* GetHistogramById(ID id);
template<ID id>
class AutoTimer {
public:

View File

@ -97,6 +97,7 @@ HISTOGRAM(IMAGE_DECODE_LATENCY, 50, 5000000, 100, EXPONENTIAL, "Time spent deco
HISTOGRAM(IMAGE_DECODE_TIME, 50, 50000000, 100, EXPONENTIAL, "Time spent decoding an image (us)")
HISTOGRAM(IMAGE_DECODE_ON_DRAW_LATENCY, 50, 50000000, 100, EXPONENTIAL, "Time from starting a decode to it showing up on the screen (us)")
HISTOGRAM(IMAGE_DECODE_CHUNKS, 1, 500, 50, EXPONENTIAL, "Number of chunks per decode attempt")
HISTOGRAM(IMAGE_DECODE_COUNT, 1, 500, 50, EXPONENTIAL, "Decode count")
/**
* Networking telemetry
@ -167,6 +168,15 @@ HISTOGRAM(NETWORK_DISK_CACHE_OPEN, 1, 10000, 10, EXPONENTIAL, "Time spent openin
HISTOGRAM(NETWORK_DISK_CACHE_TRASHRENAME, 1, 10000, 10, EXPONENTIAL, "Time spent renaming bad Cache to Cache.Trash (ms)")
HISTOGRAM(NETWORK_DISK_CACHE_DELETEDIR, 1, 10000, 10, EXPONENTIAL, "Time spent deleting disk cache (ms)")
/**
* Url-Classifier telemetry
*/
#ifdef MOZ_URL_CLASSIFIER
HISTOGRAM(URLCLASSIFIER_PS_FILELOAD_TIME, 1, 1000, 10, EXPONENTIAL, "Time spent loading PrefixSet from file (ms)")
HISTOGRAM(URLCLASSIFIER_PS_CONSTRUCT_TIME, 1, 5000, 15, EXPONENTIAL, "Time spent constructing PrefixSet from DB (ms)")
HISTOGRAM(URLCLASSIFIER_PS_LOOKUP_TIME, 1, 500, 10, EXPONENTIAL, "Time spent per PrefixSet lookup (ms)")
#endif
/**
* Places telemetry.
*/

View File

@ -53,6 +53,7 @@ XPIDLSRCS = \
nsIUrlClassifierDBService.idl \
nsIUrlClassifierHashCompleter.idl \
nsIUrlClassifierStreamUpdater.idl \
nsIUrlClassifierPrefixSet.idl \
nsIUrlClassifierUtils.idl \
nsIUrlListManager.idl \
$(NULL)
@ -61,6 +62,7 @@ CPPSRCS = \
nsUrlClassifierDBService.cpp \
nsUrlClassifierStreamUpdater.cpp \
nsUrlClassifierUtils.cpp \
nsUrlClassifierPrefixSet.cpp \
nsUrlClassifierProxies.cpp \
$(NULL)

View File

@ -0,0 +1,21 @@
#include "nsISupports.idl"
#include "nsIFile.idl"
interface nsIArray;
[scriptable, uuid(42ef1d52-3351-4973-98f8-d18f089bccfa)]
interface nsIUrlClassifierPrefixSet : nsISupports
{
void setPrefixes([const, array, size_is(aLength)] in unsigned long aPrefixes,
in unsigned long aLength);
void addPrefixes([const, array, size_is(aLength)] in unsigned long aPrefixes,
in unsigned long aLength);
boolean contains(in unsigned long aPrefix);
boolean probe(in unsigned long aPrefix, in unsigned long aKey,
inout boolean aReady);
PRUint32 estimateSize();
PRUint32 getKey();
boolean isEmpty();
void loadFromFile(in nsIFile aFile);
void storeToFile(in nsIFile aFile);
};

View File

@ -45,10 +45,13 @@
#include "nsID.h"
#include "nsInterfaceHashtable.h"
#include "nsIObserver.h"
#include "nsUrlClassifierPrefixSet.h"
#include "nsIUrlClassifierHashCompleter.h"
#include "nsIUrlClassifierDBService.h"
#include "nsIURIClassifier.h"
#include "nsToolkitCompsCID.h"
#include "nsICryptoHash.h"
#include "nsICryptoHMAC.h"
// The hash length for a domain key.
#define DOMAIN_LENGTH 4
@ -99,9 +102,13 @@ private:
nsresult LookupURI(nsIURI* uri, nsIUrlClassifierCallback* c,
PRBool forceCheck, PRBool *didCheck);
// Close db connection and join the background thread if it exists.
// Close db connection and join the background thread if it exists.
nsresult Shutdown();
// Check if the key is on a known-clean host.
nsresult CheckClean(const nsACString &lookupKey,
PRBool *clean);
nsCOMPtr<nsUrlClassifierDBServiceWorker> mWorker;
nsCOMPtr<nsIUrlClassifierDBServiceWorker> mWorkerProxy;
@ -124,6 +131,10 @@ private:
// The list of tables that can use the default hash completer object.
nsTArray<nsCString> mGethashWhitelist;
// Set of prefixes known to be in the database
nsRefPtr<nsUrlClassifierPrefixSet> mPrefixSet;
nsCOMPtr<nsICryptoHash> mHash;
// Thread that we do the updates on.
static nsIThread* gDbBackgroundThread;
};

View File

@ -0,0 +1,439 @@
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 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 Url Classifier code
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
* Mehdi Mulani <mars.martian+bugmail@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either 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 "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
#include "nsTArray.h"
#include "nsUrlClassifierPrefixSet.h"
#include "nsIUrlClassifierPrefixSet.h"
#include "nsIRandomGenerator.h"
#include "nsIFile.h"
#include "nsILocalFile.h"
#include "nsToolkitCompsCID.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "mozilla/Mutex.h"
#include "mozilla/FileUtils.h"
#include "prlog.h"
using namespace mozilla;
// NSPR_LOG_MODULES=UrlClassifierPrefixSet:5
#if defined(PR_LOGGING)
static const PRLogModuleInfo *gUrlClassifierPrefixSetLog = nsnull;
#define LOG(args) PR_LOG(gUrlClassifierPrefixSetLog, PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(gUrlClassifierPrefixSetLog, 4)
#else
#define LOG(args)
#define LOG_ENABLED() (PR_FALSE)
#endif
NS_IMPL_THREADSAFE_ISUPPORTS1(nsUrlClassifierPrefixSet, nsIUrlClassifierPrefixSet)
nsUrlClassifierPrefixSet::nsUrlClassifierPrefixSet()
: mPrefixSetLock("mPrefixSetLock"),
mSetIsReady(mPrefixSetLock, "mSetIsReady"),
mHasPrefixes(PR_FALSE),
mRandomKey(0)
{
#if defined(PR_LOGGING)
if (!gUrlClassifierPrefixSetLog)
gUrlClassifierPrefixSetLog = PR_NewLogModule("UrlClassifierPrefixSet");
#endif
nsresult rv = InitKey();
if (NS_FAILED(rv)) {
LOG(("Failed to initialize PrefixSet"));
}
}
nsresult
nsUrlClassifierPrefixSet::InitKey()
{
nsCOMPtr<nsIRandomGenerator> rg =
do_GetService("@mozilla.org/security/random-generator;1");
NS_ENSURE_STATE(rg);
PRUint8 *temp;
nsresult rv = rg->GenerateRandomBytes(sizeof(mRandomKey), &temp);
NS_ENSURE_SUCCESS(rv, rv);
memcpy(&mRandomKey, temp, sizeof(mRandomKey));
NS_Free(temp);
LOG(("Initialized PrefixSet, key = %X", mRandomKey));
return NS_OK;
}
NS_IMETHODIMP
nsUrlClassifierPrefixSet::SetPrefixes(const PRUint32 * aArray, PRUint32 aLength)
{
{
MutexAutoLock lock(mPrefixSetLock);
if (mHasPrefixes) {
LOG(("Clearing PrefixSet"));
mDeltas.Clear();
mIndexPrefixes.Clear();
mIndexStarts.Clear();
mHasPrefixes = PR_FALSE;
}
}
if (aLength > 0) {
// Ensure they are sorted before adding
nsTArray<PRUint32> prefixes;
prefixes.AppendElements(aArray, aLength);
prefixes.Sort();
AddPrefixes(prefixes.Elements(), prefixes.Length());
}
return NS_OK;
}
NS_IMETHODIMP
nsUrlClassifierPrefixSet::AddPrefixes(const PRUint32 * prefixes, PRUint32 aLength)
{
if (aLength == 0) {
return NS_OK;
}
nsTArray<PRUint32> mNewIndexPrefixes(mIndexPrefixes);
nsTArray<PRUint32> mNewIndexStarts(mIndexStarts);
nsTArray<PRUint16> mNewDeltas(mDeltas);
mNewIndexPrefixes.AppendElement(prefixes[0]);
mNewIndexStarts.AppendElement(mNewDeltas.Length());
PRUint32 numOfDeltas = 0;
PRUint32 currentItem = prefixes[0];
for (PRUint32 i = 1; i < aLength; i++) {
if ((numOfDeltas >= DELTAS_LIMIT) ||
(prefixes[i] - currentItem >= MAX_INDEX_DIFF)) {
mNewIndexStarts.AppendElement(mNewDeltas.Length());
mNewIndexPrefixes.AppendElement(prefixes[i]);
numOfDeltas = 0;
} else {
PRUint16 delta = prefixes[i] - currentItem;
mNewDeltas.AppendElement(delta);
numOfDeltas++;
}
currentItem = prefixes[i];
}
mNewIndexPrefixes.Compact();
mNewIndexStarts.Compact();
mNewDeltas.Compact();
LOG(("Total number of indices: %d", mNewIndexPrefixes.Length()));
LOG(("Total number of deltas: %d", mNewDeltas.Length()));
MutexAutoLock lock(mPrefixSetLock);
// This just swaps some pointers
mIndexPrefixes.SwapElements(mNewIndexPrefixes);
mIndexStarts.SwapElements(mNewIndexStarts);
mDeltas.SwapElements(mNewDeltas);
mHasPrefixes = PR_TRUE;
mSetIsReady.NotifyAll();
return NS_OK;
}
PRUint32 nsUrlClassifierPrefixSet::BinSearch(PRUint32 start,
PRUint32 end,
PRUint32 target)
{
while (start != end && end >= start) {
PRUint32 i = start + ((end - start) >> 1);
PRUint32 value = mIndexPrefixes[i];
if (value < target) {
start = i + 1;
} else if (value > target) {
end = i - 1;
} else {
return i;
}
}
return end;
}
NS_IMETHODIMP
nsUrlClassifierPrefixSet::Contains(PRUint32 aPrefix, PRBool * aFound)
{
*aFound = PR_FALSE;
if (!mHasPrefixes) {
return NS_OK;
}
PRUint32 target = aPrefix;
// We want to do a "Price is Right" binary search, that is, we want to find
// the index of the value either equal to the target or the closest value
// that is less than the target.
//
if (target < mIndexPrefixes[0]) {
return NS_OK;
}
// |binsearch| does not necessarily return the correct index (when the
// target is not found) but rather it returns an index at least one away
// from the correct index.
// Because of this, we need to check if the target lies before the beginning
// of the indices.
PRUint32 i = BinSearch(0, mIndexPrefixes.Length() - 1, target);
if (mIndexPrefixes[i] > target && i > 0) {
i--;
}
// Now search through the deltas for the target.
PRUint32 diff = target - mIndexPrefixes[i];
PRUint32 deltaIndex = mIndexStarts[i];
PRUint32 end = (i + 1 < mIndexStarts.Length()) ? mIndexStarts[i+1]
: mDeltas.Length();
while (diff > 0 && deltaIndex < end) {
diff -= mDeltas[deltaIndex];
deltaIndex++;
}
if (diff == 0) {
*aFound = PR_TRUE;
}
return NS_OK;
}
NS_IMETHODIMP
nsUrlClassifierPrefixSet::EstimateSize(PRUint32 * aSize)
{
MutexAutoLock lock(mPrefixSetLock);
*aSize = sizeof(PRBool);
if (mHasPrefixes) {
*aSize += sizeof(PRUint16) * mDeltas.Length();
*aSize += sizeof(PRUint32) * mIndexPrefixes.Length();
*aSize += sizeof(PRUint32) * mIndexStarts.Length();
}
return NS_OK;
}
NS_IMETHODIMP
nsUrlClassifierPrefixSet::IsEmpty(PRBool * aEmpty)
{
MutexAutoLock lock(mPrefixSetLock);
*aEmpty = !mHasPrefixes;
return NS_OK;
}
NS_IMETHODIMP
nsUrlClassifierPrefixSet::GetKey(PRUint32 * aKey)
{
MutexAutoLock lock(mPrefixSetLock);
*aKey = mRandomKey;
return NS_OK;
}
NS_IMETHODIMP
nsUrlClassifierPrefixSet::Probe(PRUint32 aPrefix, PRUint32 aKey,
PRBool* aReady, PRBool* aFound)
{
MutexAutoLock lock(mPrefixSetLock);
// We might have raced here with a LoadPrefixSet call,
// loading a saved PrefixSet with another key than the one used to probe us.
// This must occur exactly between the GetKey call and the Probe call.
// This could cause a false negative immediately after browser start.
// Claim we are still busy loading instead.
if (aKey != mRandomKey) {
LOG(("Potential race condition detected, avoiding"));
*aReady = PR_FALSE;
return NS_OK;
}
// check whether we are opportunistically probing or should wait
if (*aReady) {
// we should block until we are ready
while (!mHasPrefixes) {
LOG(("Set is empty, probe must wait"));
mSetIsReady.Wait();
}
} else {
// opportunistic probe -> check if set is loaded
if (mHasPrefixes) {
*aReady = PR_TRUE;
} else {
return NS_OK;
}
}
nsresult rv = Contains(aPrefix, aFound);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
nsUrlClassifierPrefixSet::LoadFromFd(AutoFDClose & fileFd)
{
PRUint32 magic;
PRInt32 read;
read = PR_Read(fileFd, &magic, sizeof(PRUint32));
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
if (magic == PREFIXSET_VERSION_MAGIC) {
PRUint32 indexSize;
PRUint32 deltaSize;
read = PR_Read(fileFd, &mRandomKey, sizeof(PRUint32));
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
read = PR_Read(fileFd, &indexSize, sizeof(PRUint32));
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
read = PR_Read(fileFd, &deltaSize, sizeof(PRUint32));
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
if (indexSize == 0) {
LOG(("stored PrefixSet is empty!"));
return NS_ERROR_FAILURE;
}
nsTArray<PRUint32> mNewIndexPrefixes;
nsTArray<PRUint32> mNewIndexStarts;
nsTArray<PRUint16> mNewDeltas;
mNewIndexStarts.SetLength(indexSize);
mNewIndexPrefixes.SetLength(indexSize);
mNewDeltas.SetLength(deltaSize);
read = PR_Read(fileFd, mNewIndexPrefixes.Elements(), indexSize*sizeof(PRUint32));
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
read = PR_Read(fileFd, mNewIndexStarts.Elements(), indexSize*sizeof(PRUint32));
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
if (deltaSize > 0) {
read = PR_Read(fileFd, mNewDeltas.Elements(), deltaSize*sizeof(PRUint16));
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
}
MutexAutoLock lock(mPrefixSetLock);
mIndexPrefixes.SwapElements(mNewIndexPrefixes);
mIndexStarts.SwapElements(mNewIndexStarts);
mDeltas.SwapElements(mNewDeltas);
mHasPrefixes = PR_TRUE;
mSetIsReady.NotifyAll();
} else {
LOG(("Version magic mismatch, not loading"));
return NS_ERROR_FAILURE;
}
LOG(("Loading PrefixSet successful"));
return NS_OK;
}
NS_IMETHODIMP
nsUrlClassifierPrefixSet::LoadFromFile(nsIFile * aFile)
{
nsresult rv;
nsCOMPtr<nsILocalFile> file(do_QueryInterface(aFile, &rv));
NS_ENSURE_SUCCESS(rv, rv);
AutoFDClose fileFd;
rv = file->OpenNSPRFileDesc(PR_RDONLY, 0, &fileFd);
NS_ENSURE_SUCCESS(rv, rv);
return LoadFromFd(fileFd);
}
nsresult
nsUrlClassifierPrefixSet::StoreToFd(AutoFDClose & fileFd)
{
PRInt32 written;
PRUint32 magic = PREFIXSET_VERSION_MAGIC;
written = PR_Write(fileFd, &magic, sizeof(PRUint32));
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
written = PR_Write(fileFd, &mRandomKey, sizeof(PRUint32));
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
PRUint32 indexSize = mIndexStarts.Length();
PRUint32 deltaSize = mDeltas.Length();
written = PR_Write(fileFd, &indexSize, sizeof(PRUint32));
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
written = PR_Write(fileFd, &deltaSize, sizeof(PRUint32));
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
written = PR_Write(fileFd, mIndexPrefixes.Elements(), indexSize * sizeof(PRUint32));
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
written = PR_Write(fileFd, mIndexStarts.Elements(), indexSize * sizeof(PRUint32));
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
if (deltaSize > 0) {
written = PR_Write(fileFd, mDeltas.Elements(), deltaSize * sizeof(PRUint16));
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
}
LOG(("Saving PrefixSet successful\n"));
return NS_OK;
}
NS_IMETHODIMP
nsUrlClassifierPrefixSet::StoreToFile(nsIFile * aFile)
{
if (!mHasPrefixes) {
LOG(("Attempt to serialize empty PrefixSet"));
return NS_ERROR_FAILURE;
}
nsresult rv;
nsCOMPtr<nsILocalFile> file(do_QueryInterface(aFile, &rv));
NS_ENSURE_SUCCESS(rv, rv);
AutoFDClose fileFd;
rv = file->OpenNSPRFileDesc(PR_RDWR | PR_TRUNCATE | PR_CREATE_FILE,
0644, &fileFd);
NS_ENSURE_SUCCESS(rv, rv);
MutexAutoLock lock(mPrefixSetLock);
return StoreToFd(fileFd);
}

View File

@ -0,0 +1,108 @@
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 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 Url Classifier code
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
* Mehdi Mulani <mars.martian+bugmail@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either 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 nsUrlClassifierPrefixSet_h_
#define nsUrlClassifierPrefixSet_h_
#include "nsISupportsUtils.h"
#include "nsID.h"
#include "nsIFile.h"
#include "nsIUrlClassifierPrefixSet.h"
#include "nsToolkitCompsCID.h"
#include "mozilla/Mutex.h"
#include "mozilla/CondVar.h"
#include "mozilla/FileUtils.h"
class nsUrlClassifierPrefixSet : public nsIUrlClassifierPrefixSet
{
public:
nsUrlClassifierPrefixSet();
virtual ~nsUrlClassifierPrefixSet() {};
// Can send an empty Array to clean the tree
NS_IMETHOD SetPrefixes(const PRUint32* aArray, PRUint32 aLength);
// Given prefixes must be in sorted order and bigger than
// anything currently in the Prefix Set
NS_IMETHOD AddPrefixes(const PRUint32* aArray, PRUint32 aLength);
// Does the PrefixSet contain this prefix? not thread-safe
NS_IMETHOD Contains(PRUint32 aPrefix, PRBool* aFound);
// Do a lookup in the PrefixSet
// if aReady is set, we will block until there are any entries
// if not set, we will return in aReady whether we were ready or not
NS_IMETHOD Probe(PRUint32 aPrefix, PRUint32 aKey, PRBool* aReady, PRBool* aFound);
// Return the estimated size of the set on disk and in memory,
// in bytes
NS_IMETHOD EstimateSize(PRUint32* aSize);
NS_IMETHOD IsEmpty(PRBool * aEmpty);
NS_IMETHOD LoadFromFile(nsIFile* aFile);
NS_IMETHOD StoreToFile(nsIFile* aFile);
// Return a key that is used to randomize the collisions in the prefixes
NS_IMETHOD GetKey(PRUint32* aKey);
NS_DECL_ISUPPORTS
protected:
static const PRUint32 DELTAS_LIMIT = 100;
static const PRUint32 MAX_INDEX_DIFF = (1 << 16);
static const PRUint32 PREFIXSET_VERSION_MAGIC = 1;
mozilla::Mutex mPrefixSetLock;
mozilla::CondVar mSetIsReady;
PRUint32 BinSearch(PRUint32 start, PRUint32 end, PRUint32 target);
nsresult LoadFromFd(mozilla::AutoFDClose & fileFd);
nsresult StoreToFd(mozilla::AutoFDClose & fileFd);
nsresult InitKey();
// boolean indicating whether |setPrefixes| has been
// called with a non-empty array.
PRBool mHasPrefixes;
// key used to randomize hash collisions
PRUint32 mRandomKey;
// the prefix for each index.
nsTArray<PRUint32> mIndexPrefixes;
// the value corresponds to the beginning of the run
// (an index in |_deltas|) for the index
nsTArray<PRUint32> mIndexStarts;
// array containing deltas from indices.
nsTArray<PRUint16> mDeltas;
};
#endif

View File

@ -124,125 +124,4 @@ private:
nsAutoPtr<Charmap> mEscapeCharmap;
};
// An MRU list of fragments. This is used by the DB service to
// keep a set of known-clean fragments that don't need a database
// lookup.
class nsUrlClassifierFragmentSet
{
public:
nsUrlClassifierFragmentSet() : mFirst(nsnull), mLast(nsnull), mCapacity(16) {}
PRBool Init(PRUint32 maxEntries) {
mCapacity = maxEntries;
if (!mEntryStorage.SetCapacity(mCapacity))
return PR_FALSE;
if (!mEntries.Init())
return PR_FALSE;
return PR_TRUE;
}
PRBool Put(const nsACString &fragment) {
Entry *entry = nsnull;
if (mEntries.Get(fragment, &entry)) {
// Remove this entry from the list, we'll add it back
// to the front.
UnlinkEntry(entry);
} else {
if (mEntryStorage.Length() < mEntryStorage.Capacity()) {
entry = mEntryStorage.AppendElement();
if (!entry)
return PR_FALSE;
} else {
// Reuse the oldest entry.
entry = mLast;
UnlinkEntry(entry);
mEntries.Remove(entry->mFragment);
}
entry->mFragment = fragment;
mEntries.Put(fragment, entry);
}
LinkEntry(entry);
return PR_TRUE;
}
PRBool Has(const nsACString &fragment, PRBool update = PR_TRUE) {
Entry *entry = nsnull;
PRBool exists = mEntries.Get(fragment, &entry);
// Move this entry to the front of the list (if it isn't already there)
if (update && exists && entry != mFirst) {
UnlinkEntry(entry);
LinkEntry(entry);
}
return exists;
}
void Clear() {
mFirst = mLast = nsnull;
mEntries.Clear();
mEntryStorage.Clear();
mEntryStorage.SetCapacity(mCapacity);
}
private:
// One entry in the set. We maintain a doubly-linked list, with
// the most recently used entry at the front.
class Entry {
public:
Entry() : mNext(nsnull), mPrev(nsnull) {};
~Entry() { }
Entry *mNext;
Entry *mPrev;
nsCString mFragment;
};
void LinkEntry(Entry *entry)
{
// Add the entry to the front of the list
entry->mPrev = nsnull;
entry->mNext = mFirst;
if (mFirst) {
mFirst->mPrev = entry;
}
mFirst = entry;
if (!mLast) {
mLast = entry;
}
}
void UnlinkEntry(Entry *entry)
{
if (entry->mPrev)
entry->mPrev->mNext = entry->mNext;
else
mFirst = entry->mNext;
if (entry->mNext)
entry->mNext->mPrev = entry->mPrev;
else
mLast = entry->mPrev;
entry->mPrev = entry->mNext = nsnull;
}
// The newest entry in the cache.
Entry *mFirst;
// The oldest entry in the cache.
Entry *mLast;
// Max entries in the cache.
PRUint32 mCapacity;
// Storage for the entries in this set.
nsTArray<Entry> mEntryStorage;
// Entry lookup by fragment.
nsDataHashtable<nsCStringHashKey, Entry*> mEntries;
};
#endif // nsUrlClassifierUtils_h_

View File

@ -1,3 +1,4 @@
//* -*- Mode: Javascript; tab-width: 8; indent-tabs-mode: nil; js-indent-level: 2 -*- *
function dumpn(s) {
dump(s + "\n");
}
@ -277,6 +278,8 @@ function runNextTest()
dbservice.setHashCompleter('test-phish-simple', null);
dumpn("running " + gTests[gNextTest]);
dump("running " + gTests[gNextTest]);
gTests[gNextTest++]();
}

View File

@ -1,3 +1,4 @@
//* -*- Mode: Javascript; tab-width: 8; indent-tabs-mode: nil; js-indent-level: 2 -*- *
// Test an add of two urls to a fresh database
function testCleanHostKeys() {
var addUrls = [ "foo.com/a" ];
@ -24,45 +25,12 @@ function testCleanHostKeys() {
});
// second call shouldn't result in a callback.
do_check_eq(result2, false);
runNextTest();
do_throw("shouldn't get a callback");
});
// The first classifier call should result in a callback.
do_check_eq(result, true);
}, updateError);
}
// Test an add of two urls to a fresh database
function testDirtyHostKeys() {
var addUrls = [ "foo.com/a" ];
var update = buildPhishingUpdate(
[
{ "chunkNum" : 1,
"urls" : addUrls
}]);
doStreamUpdate(update, function() {
var ios = Components.classes["@mozilla.org/network/io-service;1"].
getService(Components.interfaces.nsIIOService);
// Check with a dirty host key - both checks should happen.
var uri = ios.newURI("http://foo.com/b", null, null);
// Use the nsIURIClassifier interface (the
// nsIUrlClassifierDBService will always queue a lookup,
// nsIURIClassifier won't if the host key is known to be clean.
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
var result = classifier.classify(uri, function(errorCode) {
var result2 = classifier.classify(uri, function() {
runNextTest();
});
// second call should result in a callback.
do_check_eq(result2, true);
});
// The first classifier call should result in a callback.
do_check_eq(result, true);
// The first classifier call will not result in a callback
do_check_eq(result, false);
runNextTest();
}, updateError);
}
@ -71,109 +39,128 @@ function testUpdate() {
var ios = Components.classes["@mozilla.org/network/io-service;1"].
getService(Components.interfaces.nsIIOService);
// First lookup should happen...
var uri = ios.newURI("http://foo.com/a", null, null);
// Must put something in the PrefixSet
var preUrls = [ "foo.com/b" ];
var preUpdate = buildPhishingUpdate(
[
{ "chunkNum" : 1,
"urls" : preUrls
}]);
// Use the nsIURIClassifier interface (the
// nsIUrlClassifierDBService will always queue a lookup,
// nsIURIClassifier won't if the host key is known to be clean.
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
var result = classifier.classify(uri, function(errorCode) {
// This check will succeed, which will cause the key to
// be put in the clean host key cache...
doStreamUpdate(preUpdate, function() {
// First lookup won't happen...
var uri = ios.newURI("http://foo.com/a", null, null);
// Use the nsIURIClassifier interface (the
// nsIUrlClassifierDBService will always queue a lookup,
// nsIURIClassifier won't if the host key is known to be clean.
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
var result = classifier.classify(uri, function(errorCode) {
// shouldn't arrive here
do_check_eq(errorCode, Cr.NS_OK);
// Now add the url to the db...
var addUrls = [ "foo.com/a" ];
var update = buildPhishingUpdate(
[
{ "chunkNum" : 1,
"urls" : addUrls
}]);
doStreamUpdate(update, function() {
// The clean key cache should be blown now that we've
// added, and this callback should execute.
var result2 = classifier.classify(uri, function(errorCode) {
do_check_neq(errorCode, Cr.NS_OK);
runNextTest();
});
// second call should result in a callback.
do_check_eq(result2, true);
}, updateError);
do_throw("shouldn't get a callback");
});
do_check_eq(result, false);
// Now add the url to the db...
var addUrls = [ "foo.com/a" ];
var update = buildPhishingUpdate(
[
{ "chunkNum" : 2,
"urls" : addUrls
}]);
doStreamUpdate(update, function() {
var result2 = classifier.classify(uri, function(errorCode) {
do_check_neq(errorCode, Cr.NS_OK);
runNextTest();
});
// second call should result in a callback.
do_check_eq(result2, true);
}, updateError);
}, updateError);
}
function testResetFullCache() {
// First do enough queries to fill up the clean hostkey cache
var ios = Components.classes["@mozilla.org/network/io-service;1"].
getService(Components.interfaces.nsIIOService);
// Must put something in the PrefixSet
var preUrls = [ "zaz.com/b" ];
var preUpdate = buildPhishingUpdate(
[
{ "chunkNum" : 1,
"urls" : preUrls
}]);
// Use the nsIURIClassifier interface (the
// nsIUrlClassifierDBService will always queue a lookup,
// nsIURIClassifier won't if the host key is known to be clean.
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
doStreamUpdate(preUpdate, function() {
// First do enough queries to fill up the clean hostkey cache
var ios = Components.classes["@mozilla.org/network/io-service;1"].
getService(Components.interfaces.nsIIOService);
var uris1 = [
"www.foo.com/",
"www.bar.com/",
"www.blah.com/",
"www.site.com/",
"www.example.com/",
"www.test.com/",
"www.malware.com/",
"www.phishing.com/",
"www.clean.com/" ];
// Use the nsIURIClassifier interface (the
// nsIUrlClassifierDBService will always queue a lookup,
// nsIURIClassifier won't if the host key is known to be clean.
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
var uris2 = [];
var uris1 = [
"www.foo.com/",
"www.bar.com/",
"www.blah.com/",
"www.site.com/",
"www.example.com/",
"www.test.com/",
"www.malware.com/",
"www.phishing.com/",
"www.clean.com/" ];
var runSecondLookup = function() {
if (uris2.length == 0) {
runNextTest();
return;
var uris2 = [];
var runSecondLookup = function() {
if (uris2.length == 0) {
runNextTest();
return;
}
var spec = uris2.pop();
var uri = ios.newURI("http://" + spec, null, null);
var result = classifier.classify(uri, function(errorCode) {
});
runSecondLookup();
// now look up a few more times.
}
var spec = uris2.pop();
var uri = ios.newURI("http://" + spec, null, null);
var result = classifier.classify(uri, function(errorCode) {
runSecondLookup();
});
// now look up a few more times.
}
var runInitialLookup = function() {
if (uris1.length == 0) {
// We're done filling up the cache. Run an update to flush it,
// then start lookup up again.
var addUrls = [ "notgoingtocheck.com/a" ];
var update = buildPhishingUpdate(
[
{ "chunkNum" : 1,
"urls" : addUrls
}]);
doStreamUpdate(update, function() {
var runInitialLookup = function() {
if (uris1.length == 0) {
// We're done filling up the cache. Run an update to flush it,
// then start lookup up again.
var addUrls = [ "notgoingtocheck.com/a" ];
var update = buildPhishingUpdate(
[
{ "chunkNum" : 1,
"urls" : addUrls
}]);
doStreamUpdate(update, function() {
runSecondLookup();
}, updateError);
return;
}
var spec = uris1.pop();
return;
}
var spec = uris1.pop();
uris2.push(spec);
var uri = ios.newURI("http://" + spec, null, null);
var result = classifier.classify(uri, function(errorCode) {
runInitialLookup();
uris2.push(spec);
var uri = ios.newURI("http://" + spec, null, null);
var result = classifier.classify(uri, function(errorCode) {
});
// All of these classifications should succeed.
do_check_eq(result, true);
if (result) {
doNextTest();
runInitialLookup();
// None of these will generate a callback
do_check_eq(result, false);
if (!result) {
doNextTest();
}
}
}
// XXX bug 457790: dbservice.resetDatabase() doesn't have a way to
// wait to make sure it has been applied. Until this is added, we'll
// just use a timeout.
var t = new Timer(3000, runInitialLookup);
// XXX bug 457790: dbservice.resetDatabase() doesn't have a way to
// wait to make sure it has been applied. Until this is added, we'll
// just use a timeout.
var t = new Timer(3000, runInitialLookup);
}, updateError);
}
function testBug475436() {
@ -200,7 +187,6 @@ function run_test()
// directly after dbservice.resetDatabase().
testUpdate,
testCleanHostKeys,
testDirtyHostKeys,
testResetFullCache,
testBug475436
]);

View File

@ -87,12 +87,12 @@ compareQueries: function(fragments)
for (var i = 0; i < fragments.length; i++) {
expectedQueries.push(this.getHash(fragments[i]).slice(0, 4));
}
do_check_eq(this.queries.length, expectedQueries.length);
expectedQueries.sort();
this.queries.sort();
for (var i = 0; i < this.queries.length; i++) {
do_check_eq(this.queries[i], expectedQueries[i]);
}
do_check_eq(this.queries.length, expectedQueries.length);
}
};
@ -421,15 +421,23 @@ function testInvalidHashSize()
}],
12); // only 4 and 32 are legal hash sizes
var addUrls2 = [ "zaz.com/a", "xyz.com/b" ];
var update2 = buildPhishingUpdate(
[
{ "chunkNum" : 2,
"urls" : addUrls2
}],
4);
var completer = installCompleter('test-phish-simple', [[1, addUrls]], []);
var assertions = {
"tableData" : "",
"tableData" : "test-phish-simple;a:2",
"urlsDontExist" : addUrls
};
// A successful update will trigger an error
doUpdateTest([update], assertions, updateError, runNextTest);
doUpdateTest([update2, update], assertions, updateError, runNextTest);
}
function testWrongTable()

View File

@ -0,0 +1,168 @@
// newPset: returns an empty nsIUrlClassifierPrefixSet.
function newPset() {
return Cc["@mozilla.org/url-classifier/prefixset;1"]
.createInstance(Ci.nsIUrlClassifierPrefixSet);
}
// arrContains: returns true if |arr| contains the element |target|. Uses binary
// search and requires |arr| to be sorted.
function arrContains(arr, target) {
let start = 0;
let end = arr.length - 1;
let i = 0;
while (end > start) {
i = start + (end - start >> 1);
let value = arr[i];
if (value < target)
start = i+1;
else if (value > target)
end = i-1;
else
break;
}
if (start == end)
i = start;
return (!(i < 0 || i >= arr.length) && arr[i] == target);
}
// doRandomLookups: we use this to test for false membership with random input
// over the range of prefixes (unsigned 32-bits integers).
// pset: a nsIUrlClassifierPrefixSet to test.
// prefixes: an array of prefixes supposed to make up the prefix set.
// N: number of random lookups to make.
function doRandomLookups(pset, prefixes, N) {
for (let i = 0; i < N; i++) {
let randInt = prefixes[0];
while (arrContains(prefixes, randInt))
randInt = Math.floor(Math.random() * Math.pow(2, 32));
do_check_false(pset.contains(randInt));
}
}
// doExpectedLookups: we use this to test expected membership.
// pset: a nsIUrlClassifierPrefixSet to test.
// prefixes:
function doExpectedLookups(pset, prefixes, N) {
for (let i = 0; i < N; i++) {
prefixes.forEach(function (x) {
dump("Checking " + x + "\n");
do_check_true(pset.contains(x));
});
}
}
// testBasicPset: A very basic test of the prefix set to make sure that it
// exists and to give a basic example of its use.
function testBasicPset() {
let pset = Cc["@mozilla.org/url-classifier/prefixset;1"]
.createInstance(Ci.nsIUrlClassifierPrefixSet);
let prefixes = [2,100,50,2000,78000,1593203];
pset.setPrefixes(prefixes, prefixes.length);
do_check_true(pset.contains(100));
do_check_false(pset.contains(100000));
do_check_true(pset.contains(1593203));
do_check_false(pset.contains(999));
do_check_false(pset.contains(0));
}
function testDuplicates() {
let pset = Cc["@mozilla.org/url-classifier/prefixset;1"]
.createInstance(Ci.nsIUrlClassifierPrefixSet);
let prefixes = [1,1,2,2,2,3,3,3,3,3,3,5,6,6,7,7,9,9,9];
pset.setPrefixes(prefixes, prefixes.length);
do_check_true(pset.contains(1));
do_check_true(pset.contains(2));
do_check_true(pset.contains(5));
do_check_true(pset.contains(9));
do_check_false(pset.contains(4));
do_check_false(pset.contains(8));
}
function testSimplePset() {
let pset = newPset();
let prefixes = [1,2,100,400,123456789];
pset.setPrefixes(prefixes, prefixes.length);
doRandomLookups(pset, prefixes, 100);
doExpectedLookups(pset, prefixes, 1);
}
function testUnsortedPset() {
let pset = newPset();
let prefixes = [5,1,20,100,200000,100000];
pset.setPrefixes(prefixes, prefixes.length);
doRandomLookups(pset, prefixes, 100);
doExpectedLookups(pset, prefixes, 1);
}
function testReSetPrefixes() {
let pset = newPset();
let prefixes = [1, 5, 100, 1000, 150000];
pset.setPrefixes(prefixes, prefixes.length);
doExpectedLookups(pset, prefixes, 1);
let secondPrefixes = [12, 50, 300, 2000, 5000, 200000];
pset.setPrefixes(secondPrefixes, secondPrefixes.length);
doExpectedLookups(pset, secondPrefixes, 1);
for (let i = 0; i < prefixes.length; i++) {
do_check_false(pset.contains(prefixes[i]));
}
}
function testLargeSet() {
let N = 1000;
let arr = [];
for (let i = 0; i < N; i++) {
let randInt = Math.floor(Math.random() * Math.pow(2, 32));
arr.push(randInt);
}
arr.sort(function(x,y) x - y);
let pset = newPset();
pset.setPrefixes(arr, arr.length);
doExpectedLookups(pset, arr, 1);
doRandomLookups(pset, arr, 1000);
}
function testTinySet() {
let pset = Cc["@mozilla.org/url-classifier/prefixset;1"]
.createInstance(Ci.nsIUrlClassifierPrefixSet);
let prefixes = [1];
pset.setPrefixes(prefixes, prefixes.length);
do_check_true(pset.contains(1));
do_check_false(pset.contains(100000));
prefixes = [];
pset.setPrefixes(prefixes, prefixes.length);
do_check_false(pset.contains(1));
}
let tests = [testBasicPset,
testSimplePset,
testUnsortedPset,
testReSetPrefixes,
testLargeSet,
testDuplicates,
testTinySet];
function run_test() {
// None of the tests use |executeSoon| or any sort of callbacks, so we can
// just run them in succession.
for (let i = 0; i < tests.length; i++) {
dump("Running " + tests[i].name + "\n");
tests[i]();
}
}

View File

@ -27,6 +27,25 @@ function doTest(updates, assertions, expectError, clientKey)
}
}
function testFillDb() {
var add1Urls = [ "zaz.com/a", "yxz.com/c" ];
var update = "n:1000\n";
update += "i:test-phish-simple\n";
var update1 = buildBareUpdate(
[{ "chunkNum" : 1,
"urls" : add1Urls }]);
update += "u:data:," + encodeURIComponent(update1) + "\n";
var assertions = {
"tableData" : "test-phish-simple;a:1",
"urlsExist" : add1Urls
};
doTest([update], assertions, false);
}
function testSimpleForward() {
var add1Urls = [ "foo.com/a", "bar.com/c" ];
var add2Urls = [ "foo.com/b" ];
@ -61,6 +80,8 @@ function testSimpleForward() {
// Make sure that a nested forward (a forward within a forward) causes
// the update to fail.
function testNestedForward() {
testFillDb(); // Make sure the db isn't empty
var add1Urls = [ "foo.com/a", "bar.com/c" ];
var add2Urls = [ "foo.com/b" ];
@ -182,6 +203,8 @@ function testValidMAC() {
// Test a simple update with an invalid message authentication code.
function testInvalidMAC() {
testFillDb(); // Make sure the db isn't empty
var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
var update = buildPhishingUpdate(
[
@ -201,6 +224,8 @@ function testInvalidMAC() {
// Test a simple update without a message authentication code, when it is
// expecting one.
function testNoMAC() {
testFillDb(); // Make sure the db isn't empty
var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
var update = buildPhishingUpdate(
[
@ -257,6 +282,8 @@ function testValidForwardMAC() {
// Test an update with a valid message authentication code, but with
// invalid MACs on the forwards.
function testInvalidForwardMAC() {
testFillDb(); // Make sure the db isn't empty
var add1Urls = [ "foo.com/a", "bar.com/c" ];
var add2Urls = [ "foo.com/b" ];
var add3Urls = [ "bar.com/d" ];
@ -296,6 +323,8 @@ function testInvalidForwardMAC() {
// Test an update with a valid message authentication code, but no MAC
// specified for sub-urls.
function testNoForwardMAC() {
testFillDb(); // Make sure the db isn't empty
var add1Urls = [ "foo.com/a", "bar.com/c" ];
var add2Urls = [ "foo.com/b" ];
var add3Urls = [ "bar.com/d" ];
@ -362,6 +391,8 @@ gAssertions.gotRekey = function(data, cb)
// Tests a rekey request.
function testRekey() {
testFillDb();
var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
var update = buildPhishingUpdate(
[

View File

@ -8,4 +8,5 @@ tail = tail_urlclassifier.js
[test_dbservice.js]
[test_hashcompleter.js]
[test_partial.js]
[test_prefixset.js]
[test_streamupdater.js]

View File

@ -446,10 +446,6 @@ nsAppShell::PeekNextEvent()
void
nsAppShell::PostEvent(AndroidGeckoEvent *ae)
{
if (ae->Type() == AndroidGeckoEvent::ACTIVITY_STOPPING) {
PostEvent(new AndroidGeckoEvent(AndroidGeckoEvent::SURFACE_DESTROYED));
}
{
MutexAutoLock lock(mQueueLock);
if (ae->Type() == AndroidGeckoEvent::SURFACE_DESTROYED) {