mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central and inbound
This commit is contained in:
commit
faca188d59
2
CLOBBER
2
CLOBBER
@ -19,3 +19,5 @@
|
||||
#
|
||||
|
||||
Bug 921718 presumably needed a clobber due to bug 928195.
|
||||
and
|
||||
Bug 853423 - New code (inc. new function IsIPAddrLocal) is not being included in incremental builds.
|
||||
|
@ -2001,6 +2001,7 @@ GK_ATOM(DisplayPort, "_displayport")
|
||||
GK_ATOM(CriticalDisplayPort, "_critical_displayport")
|
||||
|
||||
// Names for system metrics
|
||||
GK_ATOM(color_picker_available, "color-picker-available")
|
||||
GK_ATOM(scrollbar_start_backward, "scrollbar-start-backward")
|
||||
GK_ATOM(scrollbar_start_forward, "scrollbar-start-forward")
|
||||
GK_ATOM(scrollbar_end_backward, "scrollbar-end-backward")
|
||||
@ -2038,6 +2039,7 @@ GK_ATOM(windows_version_win7, "windows-version-win7")
|
||||
GK_ATOM(windows_version_win8, "windows-version-win8")
|
||||
|
||||
// And the same again, as media query keywords.
|
||||
GK_ATOM(_moz_color_picker_available, "-moz-color-picker-available")
|
||||
GK_ATOM(_moz_scrollbar_start_backward, "-moz-scrollbar-start-backward")
|
||||
GK_ATOM(_moz_scrollbar_start_forward, "-moz-scrollbar-start-forward")
|
||||
GK_ATOM(_moz_scrollbar_end_backward, "-moz-scrollbar-end-backward")
|
||||
|
@ -26,9 +26,10 @@ BufferGrayRoots(GCMarker *gcmarker);
|
||||
class AutoCopyFreeListToArenas
|
||||
{
|
||||
JSRuntime *runtime;
|
||||
ZoneSelector selector;
|
||||
|
||||
public:
|
||||
AutoCopyFreeListToArenas(JSRuntime *rt);
|
||||
AutoCopyFreeListToArenas(JSRuntime *rt, ZoneSelector selector);
|
||||
~AutoCopyFreeListToArenas();
|
||||
};
|
||||
|
||||
@ -64,7 +65,7 @@ struct AutoPrepareForTracing
|
||||
AutoTraceSession session;
|
||||
AutoCopyFreeListToArenas copy;
|
||||
|
||||
AutoPrepareForTracing(JSRuntime *rt);
|
||||
AutoPrepareForTracing(JSRuntime *rt, ZoneSelector selector);
|
||||
};
|
||||
|
||||
class IncrementalSafety
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "js/HashTable.h"
|
||||
#include "vm/Runtime.h"
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
using namespace js;
|
||||
@ -21,7 +22,8 @@ js::TraceRuntime(JSTracer *trc)
|
||||
{
|
||||
JS_ASSERT(!IS_GC_MARKING_TRACER(trc));
|
||||
|
||||
AutoPrepareForTracing prep(trc->runtime);
|
||||
AutoLockForExclusiveAccess lock(trc->runtime);
|
||||
AutoPrepareForTracing prep(trc->runtime, WithAtoms);
|
||||
MarkRuntime(trc);
|
||||
}
|
||||
|
||||
@ -54,9 +56,10 @@ js::IterateZonesCompartmentsArenasCells(JSRuntime *rt, void *data,
|
||||
IterateArenaCallback arenaCallback,
|
||||
IterateCellCallback cellCallback)
|
||||
{
|
||||
AutoPrepareForTracing prop(rt);
|
||||
AutoLockForExclusiveAccess lock(rt);
|
||||
AutoPrepareForTracing prop(rt, WithAtoms);
|
||||
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
(*zoneCallback)(rt, data, zone);
|
||||
IterateCompartmentsArenasCells(rt, zone, data,
|
||||
compartmentCallback, arenaCallback, cellCallback);
|
||||
@ -70,7 +73,8 @@ js::IterateZoneCompartmentsArenasCells(JSRuntime *rt, Zone *zone, void *data,
|
||||
IterateArenaCallback arenaCallback,
|
||||
IterateCellCallback cellCallback)
|
||||
{
|
||||
AutoPrepareForTracing prop(rt);
|
||||
AutoLockForExclusiveAccess lock(rt);
|
||||
AutoPrepareForTracing prop(rt, WithAtoms);
|
||||
|
||||
(*zoneCallback)(rt, data, zone);
|
||||
IterateCompartmentsArenasCells(rt, zone, data,
|
||||
@ -80,7 +84,7 @@ js::IterateZoneCompartmentsArenasCells(JSRuntime *rt, Zone *zone, void *data,
|
||||
void
|
||||
js::IterateChunks(JSRuntime *rt, void *data, IterateChunkCallback chunkCallback)
|
||||
{
|
||||
AutoPrepareForTracing prep(rt);
|
||||
AutoPrepareForTracing prep(rt, SkipAtoms);
|
||||
|
||||
for (js::GCChunkSet::Range r = rt->gcChunkSet.all(); !r.empty(); r.popFront())
|
||||
chunkCallback(rt, data, r.front());
|
||||
@ -90,7 +94,7 @@ void
|
||||
js::IterateScripts(JSRuntime *rt, JSCompartment *compartment,
|
||||
void *data, IterateScriptCallback scriptCallback)
|
||||
{
|
||||
AutoPrepareForTracing prep(rt);
|
||||
AutoPrepareForTracing prep(rt, SkipAtoms);
|
||||
|
||||
if (compartment) {
|
||||
for (CellIterUnderGC i(compartment->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
@ -99,7 +103,7 @@ js::IterateScripts(JSRuntime *rt, JSCompartment *compartment,
|
||||
scriptCallback(rt, data, script);
|
||||
}
|
||||
} else {
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (CellIterUnderGC i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next())
|
||||
scriptCallback(rt, data, i.get<JSScript>());
|
||||
}
|
||||
@ -109,7 +113,7 @@ js::IterateScripts(JSRuntime *rt, JSCompartment *compartment,
|
||||
void
|
||||
js::IterateGrayObjects(Zone *zone, GCThingCallback cellCallback, void *data)
|
||||
{
|
||||
AutoPrepareForTracing prep(zone->runtimeFromMainThread());
|
||||
AutoPrepareForTracing prep(zone->runtimeFromMainThread(), SkipAtoms);
|
||||
|
||||
for (size_t finalizeKind = 0; finalizeKind <= FINALIZE_OBJECT_LAST; finalizeKind++) {
|
||||
for (CellIterUnderGC i(zone, AllocKind(finalizeKind)); !i.done(); i.next()) {
|
||||
@ -126,9 +130,10 @@ JS_IterateCompartments(JSRuntime *rt, void *data,
|
||||
{
|
||||
JS_ASSERT(!rt->isHeapBusy());
|
||||
|
||||
AutoLockForExclusiveAccess lock(rt);
|
||||
AutoPauseWorkersForTracing pause(rt);
|
||||
AutoTraceSession session(rt);
|
||||
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next())
|
||||
for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next())
|
||||
(*compartmentCallback)(rt, data, c);
|
||||
}
|
||||
|
@ -602,7 +602,7 @@ js::Nursery::collect(JSRuntime *rt, JS::gcreason::Reason reason)
|
||||
rt->gcStoreBuffer.mark(&trc); // This must happen first.
|
||||
MarkRuntime(&trc);
|
||||
Debugger::markAll(&trc);
|
||||
for (CompartmentsIter comp(rt); !comp.done(); comp.next()) {
|
||||
for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) {
|
||||
comp->markAllCrossCompartmentWrappers(&trc);
|
||||
comp->markAllInitialShapeTableEntries(&trc);
|
||||
}
|
||||
|
@ -664,7 +664,7 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots)
|
||||
JS_ASSERT(!rt->mainThread.suppressGC);
|
||||
|
||||
if (IS_GC_MARKING_TRACER(trc)) {
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
if (!c->zone()->isCollecting())
|
||||
c->markCrossCompartmentWrappers(trc);
|
||||
}
|
||||
@ -721,7 +721,7 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots)
|
||||
for (ContextIter acx(rt); !acx.done(); acx.next())
|
||||
acx->mark(trc);
|
||||
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
||||
if (IS_GC_MARKING_TRACER(trc) && !zone->isCollecting())
|
||||
continue;
|
||||
|
||||
@ -743,7 +743,7 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots)
|
||||
}
|
||||
|
||||
/* We can't use GCCompartmentsIter if we're called from TraceRuntime. */
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
if (trc->runtime->isHeapMinorCollecting())
|
||||
c->globalWriteBarriered = false;
|
||||
|
||||
@ -773,7 +773,7 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots)
|
||||
* which have been entered. Globals aren't nursery allocated so there's
|
||||
* no need to do this for minor GCs.
|
||||
*/
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next())
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
|
||||
c->mark(trc);
|
||||
|
||||
/*
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "gc/Zone.h"
|
||||
#include "js/HashTable.h"
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
using namespace js;
|
||||
@ -235,13 +236,13 @@ JS::CheckStackRoots(JSContext *cx)
|
||||
|
||||
// Can switch to the atoms compartment during analysis.
|
||||
if (IsAtomsCompartment(cx->compartment())) {
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
if (c.get()->activeAnalysis)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AutoCopyFreeListToArenas copy(rt);
|
||||
AutoCopyFreeListToArenas copy(rt, WithAtoms);
|
||||
|
||||
ConservativeGCData *cgcd = &rt->conservativeGC;
|
||||
cgcd->recordStackTop();
|
||||
@ -447,7 +448,8 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
|
||||
|
||||
MinorGC(rt, JS::gcreason::API);
|
||||
|
||||
AutoPrepareForTracing prep(rt);
|
||||
AutoLockForExclusiveAccess lock(rt);
|
||||
AutoPrepareForTracing prep(rt, WithAtoms);
|
||||
|
||||
if (!IsIncrementalGCSafe(rt))
|
||||
return;
|
||||
@ -510,7 +512,7 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
|
||||
rt->gcMarker.start();
|
||||
|
||||
rt->setNeedsBarrier(true);
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
PurgeJITCaches(zone);
|
||||
zone->setNeedsBarrier(true, Zone::UpdateIon);
|
||||
zone->allocator.arenas.purge();
|
||||
@ -575,7 +577,7 @@ AssertMarkedOrAllocated(const EdgeValue &edge)
|
||||
void
|
||||
gc::EndVerifyPreBarriers(JSRuntime *rt)
|
||||
{
|
||||
AutoPrepareForTracing prep(rt);
|
||||
AutoPrepareForTracing prep(rt, SkipAtoms);
|
||||
|
||||
VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData;
|
||||
|
||||
@ -585,7 +587,7 @@ gc::EndVerifyPreBarriers(JSRuntime *rt)
|
||||
bool compartmentCreated = false;
|
||||
|
||||
/* We need to disable barriers before tracing, which may invoke barriers. */
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
if (!zone->needsBarrier())
|
||||
compartmentCreated = true;
|
||||
|
||||
@ -740,7 +742,7 @@ js::gc::EndVerifyPostBarriers(JSRuntime *rt)
|
||||
{
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
VerifyPostTracer::EdgeSet edges;
|
||||
AutoPrepareForTracing prep(rt);
|
||||
AutoPrepareForTracing prep(rt, SkipAtoms);
|
||||
|
||||
VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData;
|
||||
|
||||
|
@ -319,21 +319,39 @@ struct Zone : public JS::shadow::Zone,
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Using the atoms zone without holding the exclusive access lock is dangerous
|
||||
* because worker threads may be using it simultaneously. Therefore, it's
|
||||
* better to skip the atoms zone when iterating over zones. If you need to
|
||||
* iterate over the atoms zone, consider taking the exclusive access lock first.
|
||||
*/
|
||||
enum ZoneSelector {
|
||||
WithAtoms,
|
||||
SkipAtoms
|
||||
};
|
||||
|
||||
class ZonesIter {
|
||||
private:
|
||||
JS::Zone **it, **end;
|
||||
|
||||
public:
|
||||
ZonesIter(JSRuntime *rt) {
|
||||
ZonesIter(JSRuntime *rt, ZoneSelector selector) {
|
||||
it = rt->zones.begin();
|
||||
end = rt->zones.end();
|
||||
|
||||
if (selector == SkipAtoms) {
|
||||
JS_ASSERT(rt->isAtomsZone(*it));
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
bool done() const { return it == end; }
|
||||
|
||||
void next() {
|
||||
JS_ASSERT(!done());
|
||||
it++;
|
||||
do {
|
||||
it++;
|
||||
} while (!done() && (*it)->usedByExclusiveThread);
|
||||
}
|
||||
|
||||
JS::Zone *get() const {
|
||||
@ -383,8 +401,15 @@ class CompartmentsIterT
|
||||
CompartmentsIterT(JSRuntime *rt)
|
||||
: zone(rt)
|
||||
{
|
||||
JS_ASSERT(!zone.done());
|
||||
comp.construct(zone);
|
||||
if (!zone.done())
|
||||
comp.construct(zone);
|
||||
}
|
||||
|
||||
CompartmentsIterT(JSRuntime *rt, ZoneSelector selector)
|
||||
: zone(rt, selector)
|
||||
{
|
||||
if (!zone.done())
|
||||
comp.construct(zone);
|
||||
}
|
||||
|
||||
bool done() const { return zone.done(); }
|
||||
|
@ -904,7 +904,7 @@ jit::AddSizeOfBaselineData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf,
|
||||
void
|
||||
jit::ToggleBaselineSPS(JSRuntime *runtime, bool enable)
|
||||
{
|
||||
for (ZonesIter zone(runtime); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (gc::CellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (!script->hasBaselineScript())
|
||||
|
@ -260,7 +260,7 @@ js::DestroyContext(JSContext *cx, DestroyContextMode mode)
|
||||
* Dump remaining type inference results while we still have a context.
|
||||
* This printing depends on atoms still existing.
|
||||
*/
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next())
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
|
||||
c->types.print(cx, false);
|
||||
}
|
||||
if (mode == DCM_FORCE_GC) {
|
||||
|
@ -155,7 +155,7 @@ JS::PrepareZoneForGC(Zone *zone)
|
||||
JS_FRIEND_API(void)
|
||||
JS::PrepareForFullGC(JSRuntime *rt)
|
||||
{
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next())
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
|
||||
zone->scheduleGC();
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ JS::PrepareForIncrementalGC(JSRuntime *rt)
|
||||
if (!JS::IsIncrementalGCInProgress(rt))
|
||||
return;
|
||||
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
if (zone->wasGCStarted())
|
||||
PrepareZoneForGC(zone);
|
||||
}
|
||||
@ -174,7 +174,7 @@ JS::PrepareForIncrementalGC(JSRuntime *rt)
|
||||
JS_FRIEND_API(bool)
|
||||
JS::IsGCScheduled(JSRuntime *rt)
|
||||
{
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
if (zone->isGCScheduled())
|
||||
return true;
|
||||
}
|
||||
|
@ -1010,7 +1010,7 @@ js_FinishGC(JSRuntime *rt)
|
||||
#endif
|
||||
|
||||
/* Delete all remaining zones. */
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
|
||||
js_delete(comp.get());
|
||||
js_delete(zone.get());
|
||||
@ -1908,7 +1908,7 @@ size_t
|
||||
GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
{
|
||||
size_t size = stack.sizeOfExcludingThis(mallocSizeOf);
|
||||
for (ZonesIter zone(runtime); !zone.done(); zone.next())
|
||||
for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next())
|
||||
size += zone->gcGrayRoots.sizeOfExcludingThis(mallocSizeOf);
|
||||
return size;
|
||||
}
|
||||
@ -2208,7 +2208,7 @@ static void
|
||||
AssertBackgroundSweepingFinished(JSRuntime *rt)
|
||||
{
|
||||
JS_ASSERT(!rt->gcSweepingZones);
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
for (unsigned i = 0; i < FINALIZE_LIMIT; ++i) {
|
||||
JS_ASSERT(!zone->allocator.arenas.arenaListsToSweep[i]);
|
||||
JS_ASSERT(zone->allocator.arenas.doneBackgroundFinalize(AllocKind(i)));
|
||||
@ -2771,7 +2771,7 @@ CheckForCompartmentMismatches(JSRuntime *rt)
|
||||
CompartmentCheckTracer trc;
|
||||
JS_TracerInit(&trc, rt, CheckCompartmentCallback);
|
||||
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
||||
trc.zone = zone;
|
||||
for (size_t thingKind = 0; thingKind < FINALIZE_LAST; thingKind++) {
|
||||
for (CellIterUnderGC i(zone, AllocKind(thingKind)); !i.done(); i.next()) {
|
||||
@ -2798,7 +2798,7 @@ BeginMarkPhase(JSRuntime *rt)
|
||||
rt->gcIsFull = true;
|
||||
bool any = false;
|
||||
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
/* Assert that zone state is as we expect */
|
||||
JS_ASSERT(!zone->isCollecting());
|
||||
JS_ASSERT(!zone->compartments.empty());
|
||||
@ -2820,7 +2820,7 @@ BeginMarkPhase(JSRuntime *rt)
|
||||
zone->setPreservingCode(false);
|
||||
}
|
||||
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) {
|
||||
JS_ASSERT(!c->gcLiveArrayBuffers);
|
||||
c->marked = false;
|
||||
if (ShouldPreserveJITCode(c, currentTime))
|
||||
@ -2953,7 +2953,7 @@ BeginMarkPhase(JSRuntime *rt)
|
||||
*/
|
||||
|
||||
/* Set the maybeAlive flag based on cross-compartment edges. */
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
|
||||
Cell *dst = e.front().key.wrapped;
|
||||
dst->tenuredZone()->maybeAlive = true;
|
||||
@ -3293,7 +3293,7 @@ AssertNeedsBarrierFlagsConsistent(JSRuntime *rt)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
bool anyNeedsBarrier = false;
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next())
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
|
||||
anyNeedsBarrier |= zone->needsBarrier();
|
||||
JS_ASSERT(rt->needsBarrier() == anyNeedsBarrier);
|
||||
#endif
|
||||
@ -3307,7 +3307,7 @@ DropStringWrappers(JSRuntime *rt)
|
||||
* us to sweep the wrappers in all compartments every time we sweep a
|
||||
* compartment group.
|
||||
*/
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
|
||||
if (e.front().key.kind == CrossCompartmentKey::StringWrapper)
|
||||
e.removeFront();
|
||||
@ -3856,7 +3856,7 @@ BeginSweepPhase(JSRuntime *rt, bool lastGC)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
JS_ASSERT(!c->gcIncomingGrayPointers);
|
||||
for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
|
||||
if (e.front().key.kind != CrossCompartmentKey::StringWrapper)
|
||||
@ -3966,7 +3966,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC)
|
||||
* newly created zones. Can only change from full to not full.
|
||||
*/
|
||||
if (rt->gcIsFull) {
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
if (!zone->isCollecting()) {
|
||||
rt->gcIsFull = false;
|
||||
break;
|
||||
@ -3981,7 +3981,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC)
|
||||
* prevent the cycle collector from collecting some dead objects.
|
||||
*/
|
||||
if (rt->gcFoundBlackGrayEdges) {
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
if (!zone->isCollecting())
|
||||
zone->allocator.arenas.unmarkAll();
|
||||
}
|
||||
@ -4057,7 +4057,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC)
|
||||
SweepZones(&fop, lastGC);
|
||||
}
|
||||
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
zone->setGCLastBytes(zone->gcBytes, gckind);
|
||||
if (zone->isCollecting()) {
|
||||
JS_ASSERT(zone->isGCFinished());
|
||||
@ -4077,7 +4077,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC)
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
JS_ASSERT(!c->gcIncomingGrayPointers);
|
||||
JS_ASSERT(!c->gcLiveArrayBuffers);
|
||||
|
||||
@ -4165,7 +4165,7 @@ AutoGCSession::~AutoGCSession()
|
||||
#endif
|
||||
|
||||
/* Clear gcMallocBytes for all compartments */
|
||||
for (ZonesIter zone(runtime); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) {
|
||||
zone->resetGCMallocBytes();
|
||||
zone->unscheduleGC();
|
||||
}
|
||||
@ -4173,19 +4173,39 @@ AutoGCSession::~AutoGCSession()
|
||||
runtime->resetGCMallocBytes();
|
||||
}
|
||||
|
||||
AutoCopyFreeListToArenas::AutoCopyFreeListToArenas(JSRuntime *rt)
|
||||
: runtime(rt)
|
||||
AutoCopyFreeListToArenas::AutoCopyFreeListToArenas(JSRuntime *rt, ZoneSelector selector)
|
||||
: runtime(rt),
|
||||
selector(selector)
|
||||
{
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next())
|
||||
for (ZonesIter zone(rt, selector); !zone.done(); zone.next())
|
||||
zone->allocator.arenas.copyFreeListsToArenas();
|
||||
}
|
||||
|
||||
AutoCopyFreeListToArenas::~AutoCopyFreeListToArenas()
|
||||
{
|
||||
for (ZonesIter zone(runtime); !zone.done(); zone.next())
|
||||
for (ZonesIter zone(runtime, selector); !zone.done(); zone.next())
|
||||
zone->allocator.arenas.clearFreeListsInArenas();
|
||||
}
|
||||
|
||||
class AutoCopyFreeListToArenasForGC
|
||||
{
|
||||
JSRuntime *runtime;
|
||||
|
||||
public:
|
||||
AutoCopyFreeListToArenasForGC(JSRuntime *rt) : runtime(rt) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
//if (zone->canCollect())
|
||||
zone->allocator.arenas.copyFreeListsToArenas();
|
||||
}
|
||||
}
|
||||
~AutoCopyFreeListToArenasForGC() {
|
||||
for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) {
|
||||
//if (zone->canCollect())
|
||||
zone->allocator.arenas.clearFreeListsInArenas();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
IncrementalCollectSlice(JSRuntime *rt,
|
||||
int64_t budget,
|
||||
@ -4201,7 +4221,7 @@ ResetIncrementalGC(JSRuntime *rt, const char *reason)
|
||||
|
||||
case MARK: {
|
||||
/* Cancel any ongoing marking. */
|
||||
AutoCopyFreeListToArenas copy(rt);
|
||||
AutoCopyFreeListToArenasForGC copy(rt);
|
||||
|
||||
rt->gcMarker.reset();
|
||||
rt->gcMarker.stop();
|
||||
@ -4229,7 +4249,7 @@ ResetIncrementalGC(JSRuntime *rt, const char *reason)
|
||||
case SWEEP:
|
||||
rt->gcMarker.reset();
|
||||
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next())
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
|
||||
zone->scheduledForDestruction = false;
|
||||
|
||||
/* Finish sweeping the current zone group, then abort. */
|
||||
@ -4249,10 +4269,10 @@ ResetIncrementalGC(JSRuntime *rt, const char *reason)
|
||||
rt->gcStats.reset(reason);
|
||||
|
||||
#ifdef DEBUG
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next())
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
|
||||
JS_ASSERT(!c->gcLiveArrayBuffers);
|
||||
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
JS_ASSERT(!zone->needsBarrier());
|
||||
for (unsigned i = 0; i < FINALIZE_LIMIT; ++i)
|
||||
JS_ASSERT(!zone->allocator.arenas.arenaListsToSweep[i]);
|
||||
@ -4307,7 +4327,7 @@ AutoGCSlice::~AutoGCSlice()
|
||||
{
|
||||
/* We can't use GCZonesIter if this is the end of the last slice. */
|
||||
bool haveBarriers = false;
|
||||
for (ZonesIter zone(runtime); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) {
|
||||
if (zone->isGCMarking()) {
|
||||
zone->setNeedsBarrier(true, Zone::UpdateIon);
|
||||
zone->allocator.arenas.prepareForIncrementalGC(runtime);
|
||||
@ -4339,7 +4359,7 @@ IncrementalCollectSlice(JSRuntime *rt,
|
||||
JS::gcreason::Reason reason,
|
||||
JSGCInvocationKind gckind)
|
||||
{
|
||||
AutoCopyFreeListToArenas copy(rt);
|
||||
AutoCopyFreeListToArenasForGC copy(rt);
|
||||
AutoGCSlice slice(rt);
|
||||
|
||||
bool lastGC = (reason == JS::gcreason::DESTROY_RUNTIME);
|
||||
@ -4504,7 +4524,7 @@ BudgetIncrementalGC(JSRuntime *rt, int64_t *budget)
|
||||
}
|
||||
|
||||
bool reset = false;
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
if (zone->gcBytes >= zone->gcTriggerBytes) {
|
||||
*budget = SliceBudget::Unlimited;
|
||||
rt->gcStats.nonincremental("allocation trigger");
|
||||
@ -4682,7 +4702,7 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget,
|
||||
int zoneCount = 0;
|
||||
int compartmentCount = 0;
|
||||
int collectedCount = 0;
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
if (rt->gcMode == JSGC_MODE_GLOBAL)
|
||||
zone->scheduleGC();
|
||||
|
||||
@ -4695,7 +4715,7 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget,
|
||||
collectedCount++;
|
||||
}
|
||||
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next())
|
||||
for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next())
|
||||
compartmentCount++;
|
||||
|
||||
rt->gcShouldCleanUpEverything = ShouldCleanUpEverything(rt, reason, gckind);
|
||||
@ -4767,7 +4787,7 @@ js::GCFinalSlice(JSRuntime *rt, JSGCInvocationKind gckind, JS::gcreason::Reason
|
||||
static bool
|
||||
ZonesSelected(JSRuntime *rt)
|
||||
{
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
if (zone->isGCScheduled())
|
||||
return true;
|
||||
}
|
||||
@ -4836,11 +4856,11 @@ AutoFinishGC::AutoFinishGC(JSRuntime *rt)
|
||||
gc::FinishBackgroundFinalize(rt);
|
||||
}
|
||||
|
||||
AutoPrepareForTracing::AutoPrepareForTracing(JSRuntime *rt)
|
||||
AutoPrepareForTracing::AutoPrepareForTracing(JSRuntime *rt, ZoneSelector selector)
|
||||
: finish(rt),
|
||||
pause(rt),
|
||||
session(rt),
|
||||
copy(rt)
|
||||
copy(rt, selector)
|
||||
{
|
||||
RecordNativeStackTopForGC(rt);
|
||||
}
|
||||
@ -4896,7 +4916,7 @@ void
|
||||
gc::MergeCompartments(JSCompartment *source, JSCompartment *target)
|
||||
{
|
||||
JSRuntime *rt = source->runtimeFromMainThread();
|
||||
AutoPrepareForTracing prepare(rt);
|
||||
AutoPrepareForTracing prepare(rt, SkipAtoms);
|
||||
|
||||
// Cleanup tables and other state in the source compartment that will be
|
||||
// meaningless after merging into the target compartment.
|
||||
@ -5031,7 +5051,7 @@ void
|
||||
js::ReleaseAllJITCode(FreeOp *fop)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
for (ZonesIter zone(fop->runtime()); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(fop->runtime(), SkipAtoms); !zone.done(); zone.next()) {
|
||||
|
||||
# ifdef DEBUG
|
||||
/* Assert no baseline scripts are marked as active. */
|
||||
@ -5059,7 +5079,7 @@ js::ReleaseAllJITCode(FreeOp *fop)
|
||||
}
|
||||
|
||||
/* Sweep now invalidated compiler outputs from each compartment. */
|
||||
for (CompartmentsIter comp(fop->runtime()); !comp.done(); comp.next())
|
||||
for (CompartmentsIter comp(fop->runtime(), SkipAtoms); !comp.done(); comp.next())
|
||||
comp->types.clearCompilerOutputs(fop);
|
||||
#endif
|
||||
}
|
||||
@ -5134,7 +5154,7 @@ js::StopPCCountProfiling(JSContext *cx)
|
||||
if (!vec)
|
||||
return;
|
||||
|
||||
for (ZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (CellIter i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->hasScriptCounts && script->types) {
|
||||
|
@ -306,7 +306,7 @@ class GCZonesIter
|
||||
ZonesIter zone;
|
||||
|
||||
public:
|
||||
GCZonesIter(JSRuntime *rt) : zone(rt) {
|
||||
GCZonesIter(JSRuntime *rt) : zone(rt, WithAtoms) {
|
||||
if (!zone->isCollecting())
|
||||
next();
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ void
|
||||
WatchpointMap::traceAll(WeakMapTracer *trc)
|
||||
{
|
||||
JSRuntime *rt = trc->runtime;
|
||||
for (CompartmentsIter comp(rt); !comp.done(); comp.next()) {
|
||||
for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next()) {
|
||||
if (WatchpointMap *wpmap = comp->watchpointMap)
|
||||
wpmap->trace(trc);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ void
|
||||
WeakMapBase::traceAllMappings(WeakMapTracer *tracer)
|
||||
{
|
||||
JSRuntime *rt = tracer->runtime;
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
for (WeakMapBase *m = c->gcWeakMapList; m; m = m->next)
|
||||
m->traceMappings(tracer);
|
||||
}
|
||||
@ -440,3 +440,4 @@ js_InitWeakMapClass(JSContext *cx, HandleObject obj)
|
||||
return nullptr;
|
||||
return weakMapProto;
|
||||
}
|
||||
|
||||
|
@ -885,7 +885,7 @@ js::NukeCrossCompartmentWrappers(JSContext* cx,
|
||||
// Iterate through scopes looking for system cross compartment wrappers
|
||||
// that point to an object that shares a global with obj.
|
||||
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
if (!sourceFilter.match(c))
|
||||
continue;
|
||||
|
||||
@ -992,7 +992,7 @@ js::RemapAllWrappersForObject(JSContext *cx, JSObject *oldTargetArg,
|
||||
if (!toTransplant.reserve(cx->runtime()->numCompartments))
|
||||
return false;
|
||||
|
||||
for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
|
||||
if (WrapperMap::Ptr wp = c->lookupWrapper(origv)) {
|
||||
// We found a wrapper. Remember and root it.
|
||||
toTransplant.infallibleAppend(WrapperValue(wp));
|
||||
@ -1017,7 +1017,7 @@ js::RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter,
|
||||
|
||||
AutoWrapperVector toRecompute(cx);
|
||||
|
||||
for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
|
||||
// Filter by source compartment.
|
||||
if (!sourceFilter.match(c))
|
||||
continue;
|
||||
|
@ -1448,7 +1448,7 @@ Debugger::markAllIteratively(GCMarker *trc)
|
||||
* convoluted since the easiest way to find them is via their debuggees.
|
||||
*/
|
||||
JSRuntime *rt = trc->runtime;
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
GlobalObjectSet &debuggees = c->getDebuggees();
|
||||
for (GlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) {
|
||||
GlobalObject *global = e.front();
|
||||
@ -1950,7 +1950,7 @@ Debugger::addAllGlobalsAsDebuggees(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "addAllGlobalsAsDebuggees", args, dbg);
|
||||
AutoDebugModeGC dmgc(cx->runtime());
|
||||
for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
|
||||
if (c == dbg->object->compartment() || c->options().invisibleToDebugger)
|
||||
continue;
|
||||
c->zone()->scheduledForDestruction = false;
|
||||
@ -2629,7 +2629,7 @@ Debugger::findAllGlobals(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
|
||||
c->zone()->scheduledForDestruction = false;
|
||||
|
||||
GlobalObject *global = c->maybeGlobal();
|
||||
|
@ -487,7 +487,7 @@ JS::CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisit
|
||||
JS_ASSERT(totalArenaSize % gc::ArenaSize == 0);
|
||||
#endif
|
||||
|
||||
for (CompartmentsIter comp(rt); !comp.done(); comp.next())
|
||||
for (CompartmentsIter comp(rt, WithAtoms); !comp.done(); comp.next())
|
||||
comp->compartmentStats = nullptr;
|
||||
|
||||
size_t numDirtyChunks =
|
||||
@ -512,7 +512,7 @@ JS_PUBLIC_API(size_t)
|
||||
JS::SystemCompartmentCount(JSRuntime *rt)
|
||||
{
|
||||
size_t n = 0;
|
||||
for (CompartmentsIter comp(rt); !comp.done(); comp.next()) {
|
||||
for (CompartmentsIter comp(rt, WithAtoms); !comp.done(); comp.next()) {
|
||||
if (comp->isSystem)
|
||||
++n;
|
||||
}
|
||||
@ -523,7 +523,7 @@ JS_PUBLIC_API(size_t)
|
||||
JS::UserCompartmentCount(JSRuntime *rt)
|
||||
{
|
||||
size_t n = 0;
|
||||
for (CompartmentsIter comp(rt); !comp.done(); comp.next()) {
|
||||
for (CompartmentsIter comp(rt, WithAtoms); !comp.done(); comp.next()) {
|
||||
if (!comp->isSystem)
|
||||
++n;
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ JS_SetDebugModeForAllCompartments(JSContext *cx, bool debug)
|
||||
{
|
||||
AutoDebugModeGC dmgc(cx->runtime());
|
||||
|
||||
for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
|
||||
for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
|
||||
// Ignore special compartments (atoms, JSD compartments)
|
||||
if (c->principals) {
|
||||
if (!c->setDebugModeFromC(cx, !!debug, dmgc))
|
||||
|
@ -408,7 +408,7 @@ JSRuntime::~JSRuntime()
|
||||
sourceHook = nullptr;
|
||||
|
||||
/* Off thread compilation and parsing depend on atoms still existing. */
|
||||
for (CompartmentsIter comp(this); !comp.done(); comp.next())
|
||||
for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next())
|
||||
CancelOffThreadIonCompile(comp, nullptr);
|
||||
WaitForOffThreadParsingToFinish(this);
|
||||
|
||||
@ -421,7 +421,7 @@ JSRuntime::~JSRuntime()
|
||||
FinishCommonNames(this);
|
||||
|
||||
/* Clear debugging state to remove GC roots. */
|
||||
for (CompartmentsIter comp(this); !comp.done(); comp.next()) {
|
||||
for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next()) {
|
||||
comp->clearTraps(defaultFreeOp());
|
||||
if (WatchpointMap *wpmap = comp->watchpointMap)
|
||||
wpmap->clear();
|
||||
@ -713,7 +713,7 @@ JSRuntime::setGCMaxMallocBytes(size_t value)
|
||||
*/
|
||||
gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
|
||||
resetGCMallocBytes();
|
||||
for (ZonesIter zone(this); !zone.done(); zone.next())
|
||||
for (ZonesIter zone(this, WithAtoms); !zone.done(); zone.next())
|
||||
zone->setGCMaxMallocBytes(value);
|
||||
}
|
||||
|
||||
|
@ -3874,9 +3874,8 @@ nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
|
||||
NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
|
||||
|
||||
if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
|
||||
gfxRect bbox = nsSVGUtils::GetBBox(const_cast<nsIFrame*>(aFrame));
|
||||
return nsLayoutUtils::RoundGfxRectToAppRect(bbox,
|
||||
aFrame->PresContext()->AppUnitsPerCSSPixel()) - aFrame->GetPosition();
|
||||
// TODO: SVG needs to define what percentage translations resolve against.
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
return nsRect(nsPoint(0, 0), aFrame->GetSize());
|
||||
@ -3892,9 +3891,8 @@ nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
|
||||
nsRect result;
|
||||
|
||||
if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
|
||||
gfxRect bbox = nsSVGUtils::GetBBox(const_cast<nsIFrame*>(aFrame));
|
||||
return nsLayoutUtils::RoundGfxRectToAppRect(bbox,
|
||||
aFrame->PresContext()->AppUnitsPerCSSPixel()) - aFrame->GetPosition();
|
||||
// TODO: SVG needs to define what percentage translations resolve against.
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Iterate through the continuation list, unioning together all the
|
||||
@ -3964,56 +3962,51 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
|
||||
* a distance, it's already computed for us!
|
||||
*/
|
||||
const nsStyleDisplay* display = aFrame->StyleDisplay();
|
||||
nsRect boundingRect;
|
||||
if (aBoundsOverride) {
|
||||
boundingRect = *aBoundsOverride;
|
||||
} else if (display->mTransformOrigin[0].GetUnit() != eStyleUnit_Coord ||
|
||||
display->mTransformOrigin[1].GetUnit() != eStyleUnit_Coord) {
|
||||
// GetFrameBoundsForTransform is expensive for SVG frames and we don't need
|
||||
// it if the origin is coords (which it is by default for SVG).
|
||||
boundingRect = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
|
||||
}
|
||||
nsRect boundingRect = (aBoundsOverride ? *aBoundsOverride :
|
||||
nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
|
||||
|
||||
/* Allows us to access named variables by index. */
|
||||
float coords[2];
|
||||
nscoord boundingOffsets[2] = {boundingRect.x, boundingRect.y};
|
||||
nscoord boundingDimensions[2] = {boundingRect.width, boundingRect.height};
|
||||
nscoord frameOffsets[2] = {aFrame->GetPosition().x, aFrame->GetPosition().y};
|
||||
float coords[3];
|
||||
const nscoord* dimensions[2] =
|
||||
{&boundingRect.width, &boundingRect.height};
|
||||
|
||||
for (uint8_t index = 0; index < 2; ++index) {
|
||||
/* If the -moz-transform-origin specifies a percentage, take the percentage
|
||||
* of the size of the box.
|
||||
*/
|
||||
const nsStyleCoord &coord = display->mTransformOrigin[index];
|
||||
if (coord.GetUnit() == eStyleUnit_Percent) {
|
||||
if (coord.GetUnit() == eStyleUnit_Calc) {
|
||||
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
|
||||
coords[index] =
|
||||
NSAppUnitsToFloatPixels(boundingDimensions[index], aAppUnitsPerPixel) *
|
||||
coord.GetPercentValue() +
|
||||
NSAppUnitsToFloatPixels(boundingOffsets[index], aAppUnitsPerPixel);
|
||||
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
|
||||
calc->mPercent +
|
||||
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
|
||||
} else if (coord.GetUnit() == eStyleUnit_Percent) {
|
||||
coords[index] =
|
||||
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
|
||||
coord.GetPercentValue();
|
||||
} else {
|
||||
if (coord.GetUnit() == eStyleUnit_Calc) {
|
||||
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
|
||||
coords[index] =
|
||||
NSAppUnitsToFloatPixels(boundingDimensions[index], aAppUnitsPerPixel) *
|
||||
calc->mPercent +
|
||||
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
|
||||
} else {
|
||||
NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
|
||||
coords[index] =
|
||||
NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
|
||||
}
|
||||
if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
|
||||
// <length> values represent offsets from the origin of the SVG element's
|
||||
// user space, not the top left of its border-box, so we must
|
||||
// convert them to be relative to the border-box.
|
||||
coords[index] -= NSAppUnitsToFloatPixels(frameOffsets[index], aAppUnitsPerPixel);
|
||||
}
|
||||
NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
|
||||
coords[index] =
|
||||
NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
|
||||
}
|
||||
if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
|
||||
coord.GetUnit() != eStyleUnit_Percent) {
|
||||
// <length> values represent offsets from the origin of the SVG element's
|
||||
// user space, not the top left of its bounds, so we must adjust for that:
|
||||
nscoord offset =
|
||||
(index == 0) ? aFrame->GetPosition().x : aFrame->GetPosition().y;
|
||||
coords[index] -= NSAppUnitsToFloatPixels(offset, aAppUnitsPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
return gfxPoint3D(coords[0], coords[1],
|
||||
NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
|
||||
aAppUnitsPerPixel));
|
||||
coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
|
||||
aAppUnitsPerPixel);
|
||||
/* Adjust based on the origin of the rectangle. */
|
||||
coords[0] += NSAppUnitsToFloatPixels(boundingRect.x, aAppUnitsPerPixel);
|
||||
coords[1] += NSAppUnitsToFloatPixels(boundingRect.y, aAppUnitsPerPixel);
|
||||
|
||||
return gfxPoint3D(coords[0], coords[1], coords[2]);
|
||||
}
|
||||
|
||||
/* Returns the delta specified by the -moz-perspective-origin property.
|
||||
@ -4087,6 +4080,7 @@ nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsI
|
||||
: mFrame(aFrame)
|
||||
, mTransformList(aFrame->StyleDisplay()->mSpecifiedTransform)
|
||||
, mToTransformOrigin(GetDeltaToTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride))
|
||||
, mToPerspectiveOrigin(GetDeltaToPerspectiveOrigin(aFrame, aAppUnitsPerPixel))
|
||||
, mChildPerspective(0)
|
||||
{
|
||||
const nsStyleDisplay* parentDisp = nullptr;
|
||||
@ -4096,9 +4090,6 @@ nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsI
|
||||
}
|
||||
if (parentDisp && parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
|
||||
mChildPerspective = parentDisp->mChildPerspective.GetCoordValue();
|
||||
if (mChildPerspective > 0.0) {
|
||||
mToPerspectiveOrigin = GetDeltaToPerspectiveOrigin(aFrame, aAppUnitsPerPixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4198,7 +4189,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
|
||||
/* At the point when perspective is applied, we have been translated to the transform origin.
|
||||
* The translation to the perspective origin is the difference between these values.
|
||||
*/
|
||||
result = result * nsLayoutUtils::ChangeMatrixBasis(aProperties.GetToPerspectiveOrigin() - aProperties.mToTransformOrigin, perspective);
|
||||
result = result * nsLayoutUtils::ChangeMatrixBasis(aProperties.mToPerspectiveOrigin - aProperties.mToTransformOrigin, perspective);
|
||||
}
|
||||
|
||||
gfxPoint3D rounded(hasSVGTransforms ? newOrigin.x : NS_round(newOrigin.x),
|
||||
|
@ -3061,24 +3061,15 @@ public:
|
||||
: mFrame(nullptr)
|
||||
, mTransformList(aTransformList)
|
||||
, mToTransformOrigin(aToTransformOrigin)
|
||||
, mChildPerspective(aChildPerspective)
|
||||
, mToPerspectiveOrigin(aToPerspectiveOrigin)
|
||||
, mChildPerspective(aChildPerspective)
|
||||
{}
|
||||
|
||||
const nsIFrame* mFrame;
|
||||
const nsCSSValueList* mTransformList;
|
||||
const gfxPoint3D mToTransformOrigin;
|
||||
const gfxPoint3D mToPerspectiveOrigin;
|
||||
nscoord mChildPerspective;
|
||||
|
||||
const gfxPoint3D& GetToPerspectiveOrigin() const
|
||||
{
|
||||
NS_ASSERTION(mChildPerspective > 0, "Only valid with mChildPerspective > 0");
|
||||
return mToPerspectiveOrigin;
|
||||
}
|
||||
|
||||
private:
|
||||
// mToPerspectiveOrigin is only valid if mChildPerspective > 0.
|
||||
gfxPoint3D mToPerspectiveOrigin;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1643,7 +1643,7 @@ fuzzy-if(Android&&AndroidVersion>=15,8,300) == 625409-1.html 625409-1-ref.html
|
||||
== 630835-1.html about:blank
|
||||
== 631352-1.html 631352-1-ref.html
|
||||
skip-if(B2G) fails-if(Android) == 632423-1.html 632423-1-ref.html
|
||||
skip-if(Android||B2G) random-if(winWidget&&!d2d) == 632781-verybig.html 632781-ref.html
|
||||
skip-if(Android||B2G) random-if(winWidget) == 632781-verybig.html 632781-ref.html
|
||||
== 632781-normalsize.html 632781-ref.html
|
||||
fails-if(Android) == 633344-1.html 633344-1-ref.html
|
||||
== 634232-1.html 634232-1-ref.html
|
||||
|
@ -124,7 +124,3 @@ skip-if(B2G) == stresstest-1.html stresstest-1-ref.html # bug 773482
|
||||
== table-2b.html table-2-ref.html
|
||||
# Bug 722463
|
||||
== inline-1a.html inline-1-ref.html
|
||||
== transform-origin-svg-1a.svg transform-origin-svg-1-ref.svg
|
||||
== transform-origin-svg-1b.svg transform-origin-svg-1-ref.svg
|
||||
== transform-origin-svg-2a.svg transform-origin-svg-2-ref.svg
|
||||
== transform-origin-svg-2b.svg transform-origin-svg-2-ref.svg
|
||||
|
@ -1,3 +0,0 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg'>
|
||||
<rect x='40' y='140' width='100' height='100' fill='lime'/>
|
||||
</svg>
|
Before Width: | Height: | Size: 108 B |
@ -1,6 +0,0 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg'>
|
||||
<g transform="translate(30,30)">
|
||||
<rect x='10' y='10' width='100' height='100' fill='lime'
|
||||
style="transform:rotate(90deg); transform-origin:left bottom;"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 218 B |
@ -1,7 +0,0 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg'>
|
||||
<g transform="translate(30,30)">
|
||||
<rect x='10' y='10' width='100' height='100' fill='lime'
|
||||
style="transform:rotate(90deg); transform-origin:10px 110px;
|
||||
-webkit-transform:rotate(90deg); -webkit-transform-origin:10px 110px;"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 302 B |
@ -1,3 +0,0 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg'>
|
||||
<rect x='40' y='140' width='100' height='100' fill='lime' stroke-width='20' stroke='blue'/>
|
||||
</svg>
|
Before Width: | Height: | Size: 140 B |
@ -1,6 +0,0 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg'>
|
||||
<g transform="translate(30,30)">
|
||||
<rect x='10' y='10' width='100' height='100' fill='lime' stroke-width='20' stroke='blue'
|
||||
style="transform:rotate(90deg); transform-origin:left bottom;"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 250 B |
@ -1,7 +0,0 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg'>
|
||||
<g transform="translate(30,30)">
|
||||
<rect x='10' y='10' width='100' height='100' fill='lime' stroke-width='20' stroke='blue'
|
||||
style="transform:rotate(90deg); transform-origin:10px 110px;
|
||||
-webkit-transform:rotate(90deg); -webkit-transform-origin:10px 110px;"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 334 B |
@ -1168,6 +1168,11 @@ InitSystemMetrics()
|
||||
sSystemMetrics->AppendElement(nsGkAtoms::windows_glass);
|
||||
}
|
||||
|
||||
rv = LookAndFeel::GetInt(LookAndFeel::eIntID_ColorPickerAvailable, &metricResult);
|
||||
if (NS_SUCCEEDED(rv) && metricResult) {
|
||||
sSystemMetrics->AppendElement(nsGkAtoms::color_picker_available);
|
||||
}
|
||||
|
||||
rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsClassic, &metricResult);
|
||||
if (NS_SUCCEEDED(rv) && metricResult) {
|
||||
sSystemMetrics->AppendElement(nsGkAtoms::windows_classic);
|
||||
|
@ -495,6 +495,13 @@ nsMediaFeatures::features[] = {
|
||||
{ nullptr },
|
||||
GetIsResourceDocument
|
||||
},
|
||||
{
|
||||
&nsGkAtoms::_moz_color_picker_available,
|
||||
nsMediaFeature::eMinMaxNotAllowed,
|
||||
nsMediaFeature::eBoolInteger,
|
||||
{ &nsGkAtoms::color_picker_available },
|
||||
GetSystemMetric
|
||||
},
|
||||
{
|
||||
&nsGkAtoms::_moz_scrollbar_start_backward,
|
||||
nsMediaFeature::eMinMaxNotAllowed,
|
||||
|
@ -3765,16 +3765,14 @@ nsSVGTextFrame2::ReflowSVG()
|
||||
nsSVGEffects::UpdateEffects(this);
|
||||
}
|
||||
|
||||
// Now unset the various reflow bits. Do this before calling
|
||||
// FinishAndStoreOverflow since FinishAndStoreOverflow can require glyph
|
||||
// positions (to resolve transform-origin).
|
||||
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
|
||||
nsRect overflow = nsRect(nsPoint(0,0), mRect.Size());
|
||||
nsOverflowAreas overflowAreas(overflow, overflow);
|
||||
FinishAndStoreOverflow(overflowAreas, mRect.Size());
|
||||
|
||||
// Now unset the various reflow bits:
|
||||
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
|
||||
// XXX nsSVGContainerFrame::ReflowSVG only looks at its nsISVGChildFrame
|
||||
// children, and calls ConsiderChildOverflow on them. Does it matter
|
||||
// that ConsiderChildOverflow won't be called on our children?
|
||||
@ -3809,21 +3807,9 @@ nsSVGTextFrame2::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace,
|
||||
{
|
||||
NS_ASSERTION(GetFirstPrincipalChild(), "must have a child frame");
|
||||
|
||||
SVGBBox bbox;
|
||||
if (NS_SUBTREE_DIRTY(this)) {
|
||||
// Return an empty bbox if this frame's subtree is dirty. This may be called
|
||||
// in that situation, e.g. when we're building a display list after an
|
||||
// interrupted reflow. This can also be called during reflow before we've
|
||||
// been reflowed, e.g. if an earlier sibling is calling FinishAndStoreOverflow and
|
||||
// needs our parent's perspective matrix, which depends on the SVG bbox
|
||||
// contribution of this frame. In the latter situation, when all siblings have
|
||||
// been reflowed, the parent will compute its perspective and rerun
|
||||
// FinishAndStoreOverflow for all its children.
|
||||
return bbox;
|
||||
}
|
||||
|
||||
UpdateGlyphPositioning();
|
||||
|
||||
SVGBBox bbox;
|
||||
nsPresContext* presContext = PresContext();
|
||||
|
||||
TextRenderedRunIterator it(this);
|
||||
|
@ -51,7 +51,7 @@ foreignObject {
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
/* Set |transform-origin:0 0;| for all SVG elements except outer-<svg>,
|
||||
/* Set |transform-origin:0% 0%;| for all SVG elements except outer-<svg>,
|
||||
noting that 'svg' as a child of 'foreignObject' counts as outer-<svg>.
|
||||
*/
|
||||
*:not(svg),
|
||||
|
@ -176,6 +176,12 @@ interface nsISocketTransport : nsITransport
|
||||
*/
|
||||
const unsigned long DISABLE_IPV4 = (1 << 4);
|
||||
|
||||
/**
|
||||
* If set, indicates that the socket should not connect if the hostname
|
||||
* resolves to an RFC1918 address or IPv6 equivalent.
|
||||
*/
|
||||
const unsigned long DISABLE_RFC1918 = (1 << 5);
|
||||
|
||||
/**
|
||||
* Socket QoS/ToS markings. Valid values are IPTOS_DSCP_AFxx or
|
||||
* IPTOS_CLASS_CSx (or IPTOS_DSCP_EF, but currently no supported
|
||||
|
@ -1161,6 +1161,28 @@ nsSocketTransport::InitiateSocket()
|
||||
return NS_ERROR_OFFLINE;
|
||||
}
|
||||
|
||||
// Hosts/Proxy Hosts that are Local IP Literals should not be speculatively
|
||||
// connected - Bug 853423.
|
||||
if (mConnectionFlags & nsISocketTransport::DISABLE_RFC1918 &&
|
||||
IsIPAddrLocal(&mNetAddr)) {
|
||||
#ifdef PR_LOGGING
|
||||
if (SOCKET_LOG_ENABLED()) {
|
||||
nsAutoCString netAddrCString;
|
||||
netAddrCString.SetCapacity(kIPv6CStrBufSize);
|
||||
if (!NetAddrToString(&mNetAddr,
|
||||
netAddrCString.BeginWriting(),
|
||||
kIPv6CStrBufSize))
|
||||
netAddrCString = NS_LITERAL_CSTRING("<IP-to-string failed>");
|
||||
SOCKET_LOG(("nsSocketTransport::InitiateSocket skipping "
|
||||
"speculative connection for host [%s:%d] proxy "
|
||||
"[%s:%d] with Local IP address [%s]",
|
||||
mHost.get(), mPort, mProxyHost.get(), mProxyPort,
|
||||
netAddrCString.get()));
|
||||
}
|
||||
#endif
|
||||
return NS_ERROR_CONNECTION_REFUSED;
|
||||
}
|
||||
|
||||
//
|
||||
// find out if it is going to be ok to attach another socket to the STS.
|
||||
// if not then we have to wait for the STS to tell us that it is ok.
|
||||
|
@ -177,6 +177,32 @@ bool IsIPAddrV4Mapped(const NetAddr *addr)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsIPAddrLocal(const NetAddr *addr)
|
||||
{
|
||||
MOZ_ASSERT(addr);
|
||||
|
||||
// IPv4 RFC1918 and Link Local Addresses.
|
||||
if (addr->raw.family == AF_INET) {
|
||||
uint32_t addr32 = ntohl(addr->inet.ip);
|
||||
if (addr32 >> 24 == 0x0A || // 10/8 prefix (RFC 1918).
|
||||
addr32 >> 20 == 0xAC1 || // 172.16/12 prefix (RFC 1918).
|
||||
addr32 >> 16 == 0xC0A8 || // 192.168/16 prefix (RFC 1918).
|
||||
addr32 >> 16 == 0xA9FE) { // 169.254/16 prefix (Link Local).
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// IPv6 Unique and Link Local Addresses.
|
||||
if (addr->raw.family == AF_INET6) {
|
||||
uint16_t addr16 = ntohs(addr->inet6.ip.u16[0]);
|
||||
if (addr16 >> 9 == 0xfc >> 1 || // fc00::/7 Unique Local Address.
|
||||
addr16 >> 6 == 0xfe80 >> 6) { // fe80::/10 Link Local Address.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Not an IPv4/6 local address.
|
||||
return false;
|
||||
}
|
||||
|
||||
NetAddrElement::NetAddrElement(const PRNetAddr *prNetAddr)
|
||||
{
|
||||
PRNetAddrToNetAddr(prNetAddr, &mAddress);
|
||||
|
@ -160,6 +160,8 @@ bool IsIPAddrAny(const NetAddr *addr);
|
||||
|
||||
bool IsIPAddrV4Mapped(const NetAddr *addr);
|
||||
|
||||
bool IsIPAddrLocal(const NetAddr *addr);
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -8,6 +8,10 @@
|
||||
#include "HttpLog.h"
|
||||
|
||||
#include "nsHttpConnectionInfo.h"
|
||||
#include "mozilla/net/DNS.h"
|
||||
#include "prnetdb.h"
|
||||
|
||||
using namespace mozilla::net;
|
||||
|
||||
nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &host, int32_t port,
|
||||
nsProxyInfo* proxyInfo,
|
||||
@ -113,3 +117,19 @@ nsHttpConnectionInfo::UsingProxy()
|
||||
return !mProxyInfo->IsDirect();
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpConnectionInfo::HostIsLocalIPLiteral() const
|
||||
{
|
||||
PRNetAddr prAddr;
|
||||
// If the host/proxy host is not an IP address literal, return false.
|
||||
if (ProxyHost()) {
|
||||
if (PR_StringToNetAddr(ProxyHost(), &prAddr) != PR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
} else if (PR_StringToNetAddr(Host(), &prAddr) != PR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
NetAddr netAddr;
|
||||
PRNetAddrToNetAddr(&prAddr, &netAddr);
|
||||
return IsIPAddrLocal(&netAddr);
|
||||
}
|
||||
|
@ -92,6 +92,9 @@ public:
|
||||
// Returns true for any kind of proxy (http, socks, etc..)
|
||||
bool UsingProxy();
|
||||
|
||||
// Returns true when mHost is an RFC1918 literal.
|
||||
bool HostIsLocalIPLiteral() const;
|
||||
|
||||
private:
|
||||
mozilla::ThreadSafeAutoRefCnt mRef;
|
||||
nsCString mHashKey;
|
||||
|
@ -357,6 +357,14 @@ nsHttpConnectionMgr::SpeculativeConnect(nsHttpConnectionInfo *ci,
|
||||
LOG(("nsHttpConnectionMgr::SpeculativeConnect [ci=%s]\n",
|
||||
ci->HashKey().get()));
|
||||
|
||||
// Hosts that are Local IP Literals should not be speculatively
|
||||
// connected - Bug 853423.
|
||||
if (ci && ci->HostIsLocalIPLiteral()) {
|
||||
LOG(("nsHttpConnectionMgr::SpeculativeConnect skipping RFC1918 "
|
||||
"address [%s]", ci->Host()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<SpeculativeConnectArgs> args = new SpeculativeConnectArgs();
|
||||
|
||||
// Wrap up the callbacks and the target to ensure they're released on the target
|
||||
@ -1984,13 +1992,13 @@ nsHttpConnectionMgr::CreateTransport(nsConnectionEntry *ent,
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
nsRefPtr<nsHalfOpenSocket> sock = new nsHalfOpenSocket(ent, trans, caps);
|
||||
if (speculative)
|
||||
sock->SetSpeculative(true);
|
||||
nsresult rv = sock->SetupPrimaryStreams();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
ent->mHalfOpens.AppendElement(sock);
|
||||
mNumHalfOpenConns++;
|
||||
if (speculative)
|
||||
sock->SetSpeculative(true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2711,6 +2719,10 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
|
||||
tmpFlags |= nsISocketTransport::DISABLE_IPV6;
|
||||
}
|
||||
|
||||
if (IsSpeculative()) {
|
||||
tmpFlags |= nsISocketTransport::DISABLE_RFC1918;
|
||||
}
|
||||
|
||||
socketTransport->SetConnectionFlags(tmpFlags);
|
||||
|
||||
socketTransport->SetQoSBits(gHttpHandler->GetQoSBits());
|
||||
|
@ -1,11 +1,89 @@
|
||||
const CC = Components.Constructor;
|
||||
/* -*- Mode: JavaScript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=4 sts=4 et sw=4 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const CC = Components.Constructor;
|
||||
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||
"nsIServerSocket",
|
||||
"init");
|
||||
|
||||
var serv;
|
||||
var ios;
|
||||
|
||||
/** Example local IP addresses (literal IP address hostname).
|
||||
*
|
||||
* Note: for IPv6 Unique Local and Link Local, a wider range of addresses is
|
||||
* set aside than those most commonly used. Technically, link local addresses
|
||||
* include those beginning with fe80:: through febf::, although in practise
|
||||
* only fe80:: is used. Necko code blocks speculative connections for the wider
|
||||
* range; hence, this test considers that range too.
|
||||
*/
|
||||
var localIPv4Literals =
|
||||
[ // IPv4 RFC1918 \
|
||||
"10.0.0.1", "10.10.10.10", "10.255.255.255", // 10/8
|
||||
"172.16.0.1", "172.23.172.12", "172.31.255.255", // 172.16/20
|
||||
"192.168.0.1", "192.168.192.168", "192.168.255.255", // 192.168/16
|
||||
// IPv4 Link Local
|
||||
"169.254.0.1", "169.254.192.154", "169.254.255.255" // 169.254/16
|
||||
];
|
||||
var localIPv6Literals =
|
||||
[ // IPv6 Unique Local fc00::/7
|
||||
"fc00::1", "fdfe:dcba:9876:abcd:ef01:2345:6789:abcd",
|
||||
"fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
|
||||
// IPv6 Link Local fe80::/10
|
||||
"fe80::1", "fe80::abcd:ef01:2345:6789",
|
||||
"febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
|
||||
];
|
||||
var localIPLiterals = localIPv4Literals.concat(localIPv6Literals);
|
||||
|
||||
/** Example remote IP addresses
|
||||
*
|
||||
* Note: The test environment may not have external network access, so
|
||||
* resolving hostnames may not be possible. Thus, literals are used here, and
|
||||
* should be directly converted by the stub resolver to IP addresses.
|
||||
*/
|
||||
var remoteIPv4Literals =
|
||||
[ "93.184.216.119", // example.com
|
||||
"74.125.239.130", // google.com
|
||||
"63.245.217.105", // mozilla.org
|
||||
"173.252.110.27" // facebook.com
|
||||
];
|
||||
|
||||
var remoteIPv6Literals =
|
||||
[ "2607:f8b0:4005:802::1009", // google.com
|
||||
"2620:101:8008:5::2:1", // mozilla.org
|
||||
"2a03:2880:2110:df07:face:b00c::1" // facebook.com
|
||||
];
|
||||
|
||||
var remoteIPLiterals = remoteIPv4Literals.concat(remoteIPv6Literals);
|
||||
|
||||
/** Test function list and descriptions.
|
||||
*/
|
||||
var testList =
|
||||
[ test_speculative_connect,
|
||||
test_hostnames_resolving_to_local_addresses,
|
||||
test_hostnames_resolving_to_remote_addresses,
|
||||
test_proxies_with_local_addresses,
|
||||
test_proxies_with_remote_addresses
|
||||
];
|
||||
|
||||
var testDescription =
|
||||
[ "Expect pass with localhost",
|
||||
"Expect failure with resolved local IPs",
|
||||
"Expect success with resolved remote IPs",
|
||||
"Expect failure for proxies with local IPs",
|
||||
"Expect success for proxies with remote IPs"
|
||||
];
|
||||
|
||||
var testIdx = 0;
|
||||
var hostIdx = 0;
|
||||
|
||||
|
||||
/** TestServer
|
||||
*
|
||||
* Implements nsIServerSocket for test_speculative_connect.
|
||||
*/
|
||||
function TestServer() {
|
||||
this.listener = ServerSocket(-1, true, -1);
|
||||
this.listener.asyncListen(this);
|
||||
@ -16,25 +94,310 @@ TestServer.prototype = {
|
||||
if (iid.equals(Ci.nsIServerSocket) ||
|
||||
iid.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
onSocketAccepted: function(socket, trans) {
|
||||
try { this.listener.close(); } catch(e) {}
|
||||
do_check_true(true);
|
||||
do_test_finished();
|
||||
next_test();
|
||||
},
|
||||
|
||||
onStopListening: function(socket) {}
|
||||
};
|
||||
|
||||
/** TestOutputStreamCallback
|
||||
*
|
||||
* Implements nsIOutputStreamCallback for socket layer tests.
|
||||
*/
|
||||
function TestOutputStreamCallback(transport, hostname, proxied, expectSuccess, next) {
|
||||
this.transport = transport;
|
||||
this.hostname = hostname;
|
||||
this.proxied = proxied;
|
||||
this.expectSuccess = expectSuccess;
|
||||
this.next = next;
|
||||
this.dummyContent = "Dummy content";
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
TestOutputStreamCallback.prototype = {
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsIOutputStreamCallback) ||
|
||||
iid.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
onOutputStreamReady: function(stream) {
|
||||
do_check_neq(typeof(stream), undefined);
|
||||
try {
|
||||
stream.write(this.dummyContent, this.dummyContent.length);
|
||||
} catch (e) {
|
||||
// Spec Connect FAILED.
|
||||
do_check_instanceof(e, Ci.nsIException);
|
||||
if (this.expectSuccess) {
|
||||
// We may expect success, but the address could be unreachable
|
||||
// in the test environment, so expect errors.
|
||||
if (this.proxied) {
|
||||
do_check_true(e.result == Cr.NS_ERROR_NET_TIMEOUT ||
|
||||
e.result == Cr.NS_ERROR_PROXY_CONNECTION_REFUSED);
|
||||
} else {
|
||||
do_check_true(e.result == Cr.NS_ERROR_NET_TIMEOUT ||
|
||||
e.result == Cr.NS_ERROR_CONNECTION_REFUSED);
|
||||
}
|
||||
} else {
|
||||
// A refusal to connect speculatively should throw an error.
|
||||
do_check_eq(e.result, Cr.NS_ERROR_CONNECTION_REFUSED);
|
||||
}
|
||||
this.transport.close(Cr.NS_BINDING_ABORTED);
|
||||
this.next();
|
||||
return;
|
||||
}
|
||||
// Spec Connect SUCCEEDED.
|
||||
if (this.expectSuccess) {
|
||||
do_check_true(true, "Success for " + this.hostname);
|
||||
} else {
|
||||
do_throw("Speculative Connect should have failed for " +
|
||||
this.hostname);
|
||||
}
|
||||
this.transport.close(Cr.NS_BINDING_ABORTED);
|
||||
this.next();
|
||||
}
|
||||
};
|
||||
|
||||
/** test_speculative_connect
|
||||
*
|
||||
* Tests a basic positive case using nsIOService.SpeculativeConnect:
|
||||
* connecting to localhost.
|
||||
*/
|
||||
function test_speculative_connect() {
|
||||
serv = new TestServer();
|
||||
URI = ios.newURI("http://localhost:" + serv.listener.port + "/just/a/test", null, null);
|
||||
ios.QueryInterface(Components.interfaces.nsISpeculativeConnect)
|
||||
var URI = ios.newURI("http://localhost:" + serv.listener.port + "/just/a/test", null, null);
|
||||
ios.QueryInterface(Ci.nsISpeculativeConnect)
|
||||
.speculativeConnect(URI, null);
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
/* Speculative connections should not be allowed for hosts with local IP
|
||||
* addresses (Bug 853423). That list includes:
|
||||
* -- IPv4 RFC1918 and Link Local Addresses.
|
||||
* -- IPv6 Unique and Link Local Addresses.
|
||||
*
|
||||
* Two tests are required:
|
||||
* 1. Verify IP Literals passed to the SpeculativeConnect API.
|
||||
* 2. Verify hostnames that need to be resolved at the socket layer.
|
||||
*/
|
||||
|
||||
/** test_hostnames_resolving_to_addresses
|
||||
*
|
||||
* Common test function for resolved hostnames. Takes a list of hosts, a
|
||||
* boolean to determine if the test is expected to succeed or fail, and a
|
||||
* function to call the next test case.
|
||||
*/
|
||||
function test_hostnames_resolving_to_addresses(host, expectSuccess, next) {
|
||||
do_print(host);
|
||||
var sts = Cc["@mozilla.org/network/socket-transport-service;1"]
|
||||
.getService(Ci.nsISocketTransportService);
|
||||
do_check_neq(typeof(sts), undefined);
|
||||
var transport = sts.createTransport(null, 0, host, 80, null);
|
||||
do_check_neq(typeof(transport), undefined);
|
||||
|
||||
transport.connectionFlags = Ci.nsISocketTransport.DISABLE_RFC1918;
|
||||
transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT, 1);
|
||||
transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, 1);
|
||||
do_check_eq(1, transport.getTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT));
|
||||
|
||||
var outStream = transport.openOutputStream(Ci.nsITransport.OPEN_UNBUFFERED,0,0);
|
||||
do_check_neq(typeof(outStream), undefined);
|
||||
|
||||
var callback = new TestOutputStreamCallback(transport, host, false,
|
||||
expectSuccess,
|
||||
next);
|
||||
do_check_neq(typeof(callback), undefined);
|
||||
|
||||
// Need to get main thread pointer to ensure nsSocketTransport::AsyncWait
|
||||
// adds callback to nsOutputStreamReadyEvent on main thread, and doesn't
|
||||
// addref off the main thread.
|
||||
var gThreadManager = Cc["@mozilla.org/thread-manager;1"]
|
||||
.getService(Ci.nsIThreadManager);
|
||||
var mainThread = gThreadManager.currentThread;
|
||||
|
||||
try {
|
||||
outStream.QueryInterface(Ci.nsIAsyncOutputStream)
|
||||
.asyncWait(callback, 0, 0, mainThread);
|
||||
} catch (e) {
|
||||
do_throw("asyncWait should not fail!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* test_hostnames_resolving_to_local_addresses
|
||||
*
|
||||
* Creates an nsISocketTransport and simulates a speculative connect request
|
||||
* for a hostname that resolves to a local IP address.
|
||||
* Runs asynchronously; on test success (i.e. failure to connect), the callback
|
||||
* will call this function again until all hostnames in the test list are done.
|
||||
*
|
||||
* Note: This test also uses an IP literal for the hostname. This should be ok,
|
||||
* as the socket layer will ask for the hostname to be resolved anyway, and DNS
|
||||
* code should return a numerical version of the address internally.
|
||||
*/
|
||||
function test_hostnames_resolving_to_local_addresses() {
|
||||
if (hostIdx >= localIPLiterals.length) {
|
||||
// No more local IP addresses; move on.
|
||||
next_test();
|
||||
return;
|
||||
}
|
||||
var host = localIPLiterals[hostIdx++];
|
||||
// Test another local IP address when the current one is done.
|
||||
var next = test_hostnames_resolving_to_local_addresses;
|
||||
test_hostnames_resolving_to_addresses(host, false, next);
|
||||
}
|
||||
|
||||
/**
|
||||
* test_hostnames_resolving_to_remote_addresses
|
||||
*
|
||||
* Creates an nsISocketTransport and simulates a speculative connect request
|
||||
* for a hostname that resolves to a local IP address.
|
||||
* Runs asynchronously; on test success (i.e. failure to connect), the callback
|
||||
* will call this function again until all hostnames in the test list are done.
|
||||
*
|
||||
* Note: This test also uses an IP literal for the hostname. This should be ok,
|
||||
* as the socket layer will ask for the hostname to be resolved anyway, and DNS
|
||||
* code should return a numerical version of the address internally.
|
||||
*/
|
||||
function test_hostnames_resolving_to_remote_addresses() {
|
||||
if (hostIdx >= remoteIPLiterals.length) {
|
||||
// No more remote IP addresses; move on.
|
||||
next_test();
|
||||
return;
|
||||
}
|
||||
var host = remoteIPLiterals[hostIdx++];
|
||||
// Test another remote IP address when the current one is done.
|
||||
var next = test_hostnames_resolving_to_remote_addresses;
|
||||
test_hostnames_resolving_to_addresses(host, true, next);
|
||||
}
|
||||
|
||||
/** test_speculative_connect_with_host_list
|
||||
*
|
||||
* Common test function for resolved proxy hosts. Takes a list of hosts, a
|
||||
* boolean to determine if the test is expected to succeed or fail, and a
|
||||
* function to call the next test case.
|
||||
*/
|
||||
function test_proxies(proxyHost, expectSuccess, next) {
|
||||
do_print("Proxy: " + proxyHost);
|
||||
var sts = Cc["@mozilla.org/network/socket-transport-service;1"]
|
||||
.getService(Ci.nsISocketTransportService);
|
||||
do_check_neq(typeof(sts), undefined);
|
||||
var pps = Cc["@mozilla.org/network/protocol-proxy-service;1"]
|
||||
.getService();
|
||||
do_check_neq(typeof(pps), undefined);
|
||||
|
||||
var proxyInfo = pps.newProxyInfo("http", proxyHost, 8080, 0, 1, null);
|
||||
do_check_neq(typeof(proxyInfo), undefined);
|
||||
|
||||
var transport = sts.createTransport(null, 0, "dummyHost", 80, proxyInfo);
|
||||
do_check_neq(typeof(transport), undefined);
|
||||
|
||||
transport.connectionFlags = Ci.nsISocketTransport.DISABLE_RFC1918;
|
||||
|
||||
transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT, 1);
|
||||
do_check_eq(1, transport.getTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT));
|
||||
transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, 1);
|
||||
|
||||
var outStream = transport.openOutputStream(Ci.nsITransport.OPEN_UNBUFFERED,0,0);
|
||||
do_check_neq(typeof(outStream), undefined);
|
||||
|
||||
var callback = new TestOutputStreamCallback(transport, proxyHost, true,
|
||||
expectSuccess,
|
||||
next);
|
||||
do_check_neq(typeof(callback), undefined);
|
||||
|
||||
// Need to get main thread pointer to ensure nsSocketTransport::AsyncWait
|
||||
// adds callback to nsOutputStreamReadyEvent on main thread, and doesn't
|
||||
// addref off the main thread.
|
||||
var gThreadManager = Cc["@mozilla.org/thread-manager;1"]
|
||||
.getService(Ci.nsIThreadManager);
|
||||
var mainThread = gThreadManager.currentThread;
|
||||
|
||||
try {
|
||||
outStream.QueryInterface(Ci.nsIAsyncOutputStream)
|
||||
.asyncWait(callback, 0, 0, mainThread);
|
||||
} catch (e) {
|
||||
do_throw("asyncWait should not fail!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* test_proxies_with_local_addresses
|
||||
*
|
||||
* Creates an nsISocketTransport and simulates a speculative connect request
|
||||
* for a proxy that resolves to a local IP address.
|
||||
* Runs asynchronously; on test success (i.e. failure to connect), the callback
|
||||
* will call this function again until all proxies in the test list are done.
|
||||
*
|
||||
* Note: This test also uses an IP literal for the proxy. This should be ok,
|
||||
* as the socket layer will ask for the proxy to be resolved anyway, and DNS
|
||||
* code should return a numerical version of the address internally.
|
||||
*/
|
||||
function test_proxies_with_local_addresses() {
|
||||
if (hostIdx >= localIPLiterals.length) {
|
||||
// No more local IP addresses; move on.
|
||||
next_test();
|
||||
return;
|
||||
}
|
||||
var host = localIPLiterals[hostIdx++];
|
||||
// Test another local IP address when the current one is done.
|
||||
var next = test_proxies_with_local_addresses;
|
||||
test_proxies(host, false, next);
|
||||
}
|
||||
|
||||
/**
|
||||
* test_proxies_with_remote_addresses
|
||||
*
|
||||
* Creates an nsISocketTransport and simulates a speculative connect request
|
||||
* for a proxy that resolves to a local IP address.
|
||||
* Runs asynchronously; on test success (i.e. failure to connect), the callback
|
||||
* will call this function again until all proxies in the test list are done.
|
||||
*
|
||||
* Note: This test also uses an IP literal for the proxy. This should be ok,
|
||||
* as the socket layer will ask for the proxy to be resolved anyway, and DNS
|
||||
* code should return a numerical version of the address internally.
|
||||
*/
|
||||
function test_proxies_with_remote_addresses() {
|
||||
if (hostIdx >= remoteIPLiterals.length) {
|
||||
// No more local IP addresses; move on.
|
||||
next_test();
|
||||
return;
|
||||
}
|
||||
var host = remoteIPLiterals[hostIdx++];
|
||||
// Test another local IP address when the current one is done.
|
||||
var next = test_proxies_with_remote_addresses;
|
||||
test_proxies(host, true, next);
|
||||
}
|
||||
|
||||
/** next_test
|
||||
*
|
||||
* Calls the next test in testList. Each test is responsible for calling this
|
||||
* function when its test cases are complete.
|
||||
*/
|
||||
function next_test() {
|
||||
if (testIdx >= testList.length) {
|
||||
// No more tests; we're done.
|
||||
do_test_finished();
|
||||
return;
|
||||
}
|
||||
do_print("SpeculativeConnect: " + testDescription[testIdx]);
|
||||
hostIdx = 0;
|
||||
// Start next test in list.
|
||||
testList[testIdx++]();
|
||||
}
|
||||
|
||||
/** run_test
|
||||
*
|
||||
* Main entry function for test execution.
|
||||
*/
|
||||
function run_test() {
|
||||
ios = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
|
||||
do_test_pending();
|
||||
next_test();
|
||||
}
|
||||
|
||||
|
@ -7,19 +7,19 @@ class ScreenshotTests(MarionetteTestCase):
|
||||
test_url = self.marionette.absolute_url('html5Page.html')
|
||||
self.marionette.navigate(test_url)
|
||||
el = self.marionette.find_element('id', 'red')
|
||||
self.assertEqual('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAVUlEQVRoge3PsQ0AIAzAsI78fzBwBhHykD2ePev80LweAAGJB1ILpBZILZBaILVAaoHUAqkFUgukFkgtkFogtUBqgdQCqQVSC6QWSC2QWiC1QGp9A7ma+7nyXgOpzQAAAABJRU5ErkJggg==',
|
||||
self.assertEqual('iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAVUlEQVRoge3PsQ0AIAzAsI78fzBwBhHykD2ePev80LweAAGJB1ILpBZILZBaILVAaoHUAqkFUgukFkgtkFogtUBqgdQCqQVSC6QWSC2QWiC1QGp9A7ma+7nyXgOpzQAAAABJRU5ErkJggg==',
|
||||
self.marionette.screenshot(element=el))
|
||||
|
||||
def testWeCanTakeAScreenShotWithHighlightOfAnElement(self):
|
||||
test_url = self.marionette.absolute_url('html5Page.html')
|
||||
self.marionette.navigate(test_url)
|
||||
el = self.marionette.find_element('id', 'green')
|
||||
self.assertEqual('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAV0lEQVRoge3PQRGAQAwAsWINvXgsNnI3+4iAzM7sDWZn9vneoxXRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNHcF7nBD/Ha5Ye4BbsYAAAAAElFTkSuQmCC',
|
||||
self.assertEqual('iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAV0lEQVRoge3PQRGAQAwAsWINvXgsNnI3+4iAzM7sDWZn9vneoxXRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNHcF7nBD/Ha5Ye4BbsYAAAAAElFTkSuQmCC',
|
||||
self.marionette.screenshot(element=el, highlights=[el]))
|
||||
|
||||
def testWeCanTakeAScreenShotEntireCanvas(self):
|
||||
test_url = self.marionette.absolute_url('html5Page.html')
|
||||
self.marionette.navigate(test_url)
|
||||
self.assertTrue('data:image/png;base64,iVBORw0KGgo' in
|
||||
self.assertTrue('iVBORw0KGgo' in
|
||||
self.marionette.screenshot())
|
||||
|
||||
|
@ -1937,7 +1937,8 @@ function screenShot(msg) {
|
||||
|
||||
// Return the Base64 String back to the client bindings and they can manage
|
||||
// saving the file to disk if it is required
|
||||
sendResponse({value:canvas.toDataURL("image/png","")}, msg.json.command_id);
|
||||
var data_url = canvas.toDataURL("image/png","");
|
||||
sendResponse({value: data_url.substring(data_url.indexOf(",") + 1)}, msg.json.command_id);
|
||||
}
|
||||
|
||||
//call register self when we get loaded
|
||||
|
@ -356,6 +356,15 @@ public:
|
||||
*/
|
||||
eIntID_SwipeAnimationEnabled,
|
||||
|
||||
/*
|
||||
* A Boolean value to determine whether we have a color picker available
|
||||
* for <input type="color"> to hook into.
|
||||
*
|
||||
* This lets us selectively enable the style for <input type="color">
|
||||
* based on whether it's functional or not.
|
||||
*/
|
||||
eIntID_ColorPickerAvailable,
|
||||
|
||||
/*
|
||||
* A boolean value indicating whether or not the device has a hardware
|
||||
* home button. Used on gaia to determine whether a home button
|
||||
|
@ -446,6 +446,9 @@ nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult)
|
||||
aResult = [NSEvent isSwipeTrackingFromScrollEventsEnabled] ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
case eIntID_ColorPickerAvailable:
|
||||
aResult = 1;
|
||||
break;
|
||||
default:
|
||||
aResult = 0;
|
||||
res = NS_ERROR_FAILURE;
|
||||
|
@ -663,6 +663,9 @@ nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult)
|
||||
case eIntID_SwipeAnimationEnabled:
|
||||
aResult = 0;
|
||||
break;
|
||||
case eIntID_ColorPickerAvailable:
|
||||
aResult = 1;
|
||||
break;
|
||||
default:
|
||||
aResult = 0;
|
||||
res = NS_ERROR_FAILURE;
|
||||
|
@ -482,6 +482,10 @@ nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult)
|
||||
case eIntID_SwipeAnimationEnabled:
|
||||
aResult = 0;
|
||||
break;
|
||||
case eIntID_ColorPickerAvailable:
|
||||
// We don't have a color picker implemented on Metro yet (bug 895464)
|
||||
aResult = (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro);
|
||||
break;
|
||||
case eIntID_UseOverlayScrollbars:
|
||||
aResult = (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user