зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
Коммит
a9b5e2819a
|
@ -0,0 +1,10 @@
|
|||
. "$topsrcdir/browser/config/mozconfigs/macosx64/nightly"
|
||||
|
||||
TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
|
||||
|
||||
ac_add_options --disable-sandbox
|
||||
ac_add_options --enable-coverage
|
||||
|
||||
export CFLAGS="-coverage"
|
||||
export CXXFLAGS="-coverage"
|
||||
export LDFLAGS="-coverage"
|
|
@ -0,0 +1,3 @@
|
|||
. "$topsrcdir/browser/config/mozconfigs/macosx64/code-coverage"
|
||||
|
||||
ac_add_options --enable-debug
|
|
@ -852,7 +852,8 @@ nsContentList::MatchSelf(nsIContent *aContent)
|
|||
}
|
||||
|
||||
void
|
||||
nsContentList::PopulateSelf(uint32_t aNeededLength)
|
||||
nsContentList::PopulateSelf(uint32_t aNeededLength,
|
||||
uint32_t aExpectedElementsIfDirty)
|
||||
{
|
||||
if (!mRootNode) {
|
||||
return;
|
||||
|
@ -861,7 +862,7 @@ nsContentList::PopulateSelf(uint32_t aNeededLength)
|
|||
ASSERT_IN_SYNC;
|
||||
|
||||
uint32_t count = mElements.Length();
|
||||
NS_ASSERTION(mState != LIST_DIRTY || count == 0,
|
||||
NS_ASSERTION(mState != LIST_DIRTY || count == aExpectedElementsIfDirty,
|
||||
"Reset() not called when setting state to LIST_DIRTY?");
|
||||
|
||||
if (count >= aNeededLength) // We're all set
|
||||
|
@ -1153,7 +1154,8 @@ nsLabelsNodeList::MaybeResetRoot(nsINode* aRootNode)
|
|||
}
|
||||
|
||||
void
|
||||
nsLabelsNodeList::PopulateSelf(uint32_t aNeededLength)
|
||||
nsLabelsNodeList::PopulateSelf(uint32_t aNeededLength,
|
||||
uint32_t aExpectedElementsIfDirty)
|
||||
{
|
||||
if (!mRootNode) {
|
||||
return;
|
||||
|
@ -1163,7 +1165,8 @@ nsLabelsNodeList::PopulateSelf(uint32_t aNeededLength)
|
|||
nsINode* cur = mRootNode;
|
||||
if (mElements.IsEmpty() && cur->IsElement() && Match(cur->AsElement())) {
|
||||
mElements.AppendElement(cur->AsElement());
|
||||
++aExpectedElementsIfDirty;
|
||||
}
|
||||
|
||||
nsContentList::PopulateSelf(aNeededLength);
|
||||
nsContentList::PopulateSelf(aNeededLength, aExpectedElementsIfDirty);
|
||||
}
|
||||
|
|
|
@ -433,8 +433,11 @@ protected:
|
|||
*
|
||||
* @param aNeededLength the length the list should have when we are
|
||||
* done (unless it exhausts the document)
|
||||
* @param aExpectedElementsIfDirty is for debugging only to
|
||||
* assert that mElements has expected number of entries.
|
||||
*/
|
||||
virtual void PopulateSelf(uint32_t aNeededLength);
|
||||
virtual void PopulateSelf(uint32_t aNeededLength,
|
||||
uint32_t aExpectedElementsIfDirty = 0);
|
||||
|
||||
/**
|
||||
* @param aContainer a content node which must be a descendant of
|
||||
|
@ -684,7 +687,10 @@ private:
|
|||
*
|
||||
* @param aNeededLength The list of length should have when we are
|
||||
* done (unless it exhausts the document).
|
||||
* @param aExpectedElementsIfDirty is for debugging only to
|
||||
* assert that mElements has expected number of entries.
|
||||
*/
|
||||
void PopulateSelf(uint32_t aNeededLength) override;
|
||||
void PopulateSelf(uint32_t aNeededLength,
|
||||
uint32_t aExpectedElementsIfDirty = 0) override;
|
||||
};
|
||||
#endif // nsContentList_h___
|
||||
|
|
|
@ -280,6 +280,15 @@ nsINode::GetParentOrHostNode() const
|
|||
nsINode*
|
||||
nsINode::SubtreeRoot() const
|
||||
{
|
||||
auto RootOfNode = [](const nsINode* aStart) -> nsINode* {
|
||||
const nsINode* node = aStart;
|
||||
const nsINode* iter = node;
|
||||
while ((iter = iter->GetParentNode())) {
|
||||
node = iter;
|
||||
}
|
||||
return const_cast<nsINode*>(node);
|
||||
};
|
||||
|
||||
// There are four cases of interest here. nsINodes that are really:
|
||||
// 1. nsIDocument nodes - Are always in the document.
|
||||
// 2.a nsIContent nodes not in a shadow tree - Are either in the document,
|
||||
|
@ -294,19 +303,18 @@ nsINode::SubtreeRoot() const
|
|||
} else if (IsContent()) {
|
||||
ShadowRoot* containingShadow = AsContent()->GetContainingShadow();
|
||||
node = containingShadow ? containingShadow : mSubtreeRoot;
|
||||
if (!node) {
|
||||
NS_WARNING("Using SubtreeRoot() on unlinked element?");
|
||||
node = RootOfNode(this);
|
||||
}
|
||||
} else {
|
||||
node = mSubtreeRoot;
|
||||
}
|
||||
NS_ASSERTION(node, "Should always have a node here!");
|
||||
MOZ_ASSERT(node, "Should always have a node here!");
|
||||
#ifdef DEBUG
|
||||
{
|
||||
const nsINode* slowNode = this;
|
||||
const nsINode* iter = slowNode;
|
||||
while ((iter = iter->GetParentNode())) {
|
||||
slowNode = iter;
|
||||
}
|
||||
|
||||
NS_ASSERTION(slowNode == node, "These should always be in sync!");
|
||||
const nsINode* slowNode = RootOfNode(this);
|
||||
MOZ_ASSERT(slowNode == node, "These should always be in sync!");
|
||||
}
|
||||
#endif
|
||||
return node;
|
||||
|
|
|
@ -205,7 +205,21 @@ WebGLContext::BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fa
|
|||
UniquePtr<FakeBlackTexture>& fakeBlackTex = *slot;
|
||||
|
||||
if (!fakeBlackTex) {
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
|
||||
if (IsWebGL2()) {
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS, 0);
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, 0);
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, 0);
|
||||
}
|
||||
|
||||
fakeBlackTex = FakeBlackTexture::Create(gl, target, fakeBlack);
|
||||
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mPixelStore_UnpackAlignment);
|
||||
if (IsWebGL2()) {
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS, mPixelStore_UnpackSkipPixels);
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, mPixelStore_UnpackSkipRows);
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, mPixelStore_UnpackSkipImages);
|
||||
}
|
||||
if (!fakeBlackTex) {
|
||||
return false;
|
||||
}
|
||||
|
@ -995,13 +1009,8 @@ WebGLContext::FakeBlackTexture::Create(gl::GLContext* gl, TexTarget target,
|
|||
gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
|
||||
gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
|
||||
|
||||
// We allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) to
|
||||
// minimize the risk of running into a driver bug in texImage2D, as it is a bit
|
||||
// unusual maybe to create 1x1 textures, and the stack may not have the alignment that
|
||||
// TexImage2D expects.
|
||||
|
||||
const webgl::DriverUnpackInfo dui = {texFormat, texFormat, LOCAL_GL_UNSIGNED_BYTE};
|
||||
UniqueBuffer zeros = moz_xcalloc(1, 16); // Infallible allocation.
|
||||
UniqueBuffer zeros = moz_xcalloc(1, 4); // Infallible allocation.
|
||||
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
|
|
|
@ -473,14 +473,13 @@ nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
}
|
||||
}
|
||||
|
||||
// We need to consider a labels element is removed from tree,
|
||||
// it needs to update labels list and its root as well.
|
||||
nsStyledElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
// Invalidate .labels list. It will be repopulated when used the next time.
|
||||
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||
if (slots && slots->mLabelsList) {
|
||||
slots->mLabelsList->MaybeResetRoot(SubtreeRoot());
|
||||
}
|
||||
|
||||
nsStyledElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
HTMLFormElement*
|
||||
|
|
|
@ -698,12 +698,16 @@ ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier&
|
|||
void
|
||||
ImageBridgeChild::UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aIdentifier)
|
||||
{
|
||||
// ImageHost is incompatible between WebRender enabled and WebRender disabled.
|
||||
// Then drop all ImageContainers' ImageClients during disabling WebRender.
|
||||
bool disablingWebRender = GetCompositorBackendType() == LayersBackend::LAYERS_WR &&
|
||||
aIdentifier.mParentBackend != LayersBackend::LAYERS_WR;
|
||||
// D3DTexture might become obsolte. To prevent to use obsoleted D3DTexture,
|
||||
// drop all ImageContainers' ImageClients.
|
||||
bool needsDrop = GetCompositorBackendType() == LayersBackend::LAYERS_D3D11 || disablingWebRender;
|
||||
|
||||
IdentifyTextureHost(aIdentifier);
|
||||
if (disablingWebRender) {
|
||||
// ImageHost is incompatible between WebRender enabled and WebRender disabled.
|
||||
// Then drop all ImageContainers' ImageClients during disabling WebRender.
|
||||
if (needsDrop) {
|
||||
nsTArray<RefPtr<ImageContainerListener> > listeners;
|
||||
{
|
||||
MutexAutoLock lock(mContainerMapLock);
|
||||
|
|
|
@ -2,7 +2,7 @@ This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
|
|||
|
||||
Our reference repository is https://github.com/khaledhosny/ots/.
|
||||
|
||||
Current revision: c903692702e888dd9bc3e62a129d01af07320ad8 (6.1.1)
|
||||
Current revision: 7c8f3fc9cf8b79edb241d94a4847968a5009e78d (7.0.0)
|
||||
|
||||
Upstream files included: LICENSE, src/, include/, tests/*.cc
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ class OpenTypeFVAR : public Table {
|
|||
bool Parse(const uint8_t* data, size_t length);
|
||||
bool Serialize(OTSStream* out);
|
||||
|
||||
const uint16_t AxisCount() const { return axisCount; }
|
||||
uint16_t AxisCount() const { return axisCount; }
|
||||
|
||||
private:
|
||||
uint16_t majorVersion;
|
||||
|
|
|
@ -154,3 +154,5 @@ bool OpenTypeGVAR::Serialize(OTSStream* out) {
|
|||
}
|
||||
|
||||
} // namespace ots
|
||||
|
||||
#undef TABLE_NAME
|
||||
|
|
|
@ -85,3 +85,5 @@ bool OpenTypeHVAR::Serialize(OTSStream* out) {
|
|||
}
|
||||
|
||||
} // namespace ots
|
||||
|
||||
#undef TABLE_NAME
|
||||
|
|
|
@ -105,3 +105,5 @@ bool OpenTypeMVAR::Serialize(OTSStream* out) {
|
|||
}
|
||||
|
||||
} // namespace ots
|
||||
|
||||
#undef TABLE_NAME
|
||||
|
|
|
@ -47,7 +47,7 @@ class OpenTypeSTAT : public Table {
|
|||
uint16_t flags;
|
||||
uint16_t valueNameID;
|
||||
Fixed value;
|
||||
static const size_t Length() {
|
||||
static size_t Length() {
|
||||
return 3 * sizeof(uint16_t) + sizeof(Fixed);
|
||||
}
|
||||
};
|
||||
|
@ -59,7 +59,7 @@ class OpenTypeSTAT : public Table {
|
|||
Fixed nominalValue;
|
||||
Fixed rangeMinValue;
|
||||
Fixed rangeMaxValue;
|
||||
static const size_t Length() {
|
||||
static size_t Length() {
|
||||
return 3 * sizeof(uint16_t) + 3 * sizeof(Fixed);
|
||||
}
|
||||
};
|
||||
|
@ -70,7 +70,7 @@ class OpenTypeSTAT : public Table {
|
|||
uint16_t valueNameID;
|
||||
Fixed value;
|
||||
Fixed linkedValue;
|
||||
static const size_t Length() {
|
||||
static size_t Length() {
|
||||
return 3 * sizeof(uint16_t) + 2 * sizeof(Fixed);
|
||||
}
|
||||
};
|
||||
|
@ -84,7 +84,7 @@ class OpenTypeSTAT : public Table {
|
|||
Fixed value;
|
||||
};
|
||||
std::vector<AxisValue> axisValues;
|
||||
const size_t Length() const {
|
||||
size_t Length() const {
|
||||
return 3 * sizeof(uint16_t) + axisValues.size() * (sizeof(uint16_t) + sizeof(Fixed));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -246,3 +246,5 @@ bool ParseVariationData(const Font* font, const uint8_t* data, size_t length,
|
|||
}
|
||||
|
||||
} // namespace ots
|
||||
|
||||
#undef TABLE_NAME
|
||||
|
|
|
@ -95,3 +95,5 @@ bool OpenTypeVVAR::Serialize(OTSStream* out) {
|
|||
}
|
||||
|
||||
} // namespace ots
|
||||
|
||||
#undef TABLE_NAME
|
||||
|
|
|
@ -6965,10 +6965,13 @@ GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoTraceSession& session)
|
|||
|
||||
namespace {
|
||||
|
||||
class AutoGCSlice {
|
||||
/*
|
||||
* Temporarily disable barriers during GC slices.
|
||||
*/
|
||||
class AutoDisableBarriers {
|
||||
public:
|
||||
explicit AutoGCSlice(JSRuntime* rt);
|
||||
~AutoGCSlice();
|
||||
explicit AutoDisableBarriers(JSRuntime* rt);
|
||||
~AutoDisableBarriers();
|
||||
|
||||
private:
|
||||
JSRuntime* runtime;
|
||||
|
@ -6977,7 +6980,7 @@ class AutoGCSlice {
|
|||
|
||||
} /* anonymous namespace */
|
||||
|
||||
AutoGCSlice::AutoGCSlice(JSRuntime* rt)
|
||||
AutoDisableBarriers::AutoDisableBarriers(JSRuntime* rt)
|
||||
: runtime(rt)
|
||||
{
|
||||
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
|
@ -6985,7 +6988,7 @@ AutoGCSlice::AutoGCSlice(JSRuntime* rt)
|
|||
* Clear needsIncrementalBarrier early so we don't do any write
|
||||
* barriers during GC. We don't need to update the Ion barriers (which
|
||||
* is expensive) because Ion code doesn't run during GC. If need be,
|
||||
* we'll update the Ion barriers in ~AutoGCSlice.
|
||||
* we'll update the Ion barriers in ~AutoDisableBarriers.
|
||||
*/
|
||||
if (zone->isGCMarking()) {
|
||||
MOZ_ASSERT(zone->needsIncrementalBarrier());
|
||||
|
@ -6995,7 +6998,7 @@ AutoGCSlice::AutoGCSlice(JSRuntime* rt)
|
|||
}
|
||||
}
|
||||
|
||||
AutoGCSlice::~AutoGCSlice()
|
||||
AutoDisableBarriers::~AutoDisableBarriers()
|
||||
{
|
||||
/* We can't use GCZonesIter if this is the end of the last slice. */
|
||||
for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) {
|
||||
|
@ -7052,7 +7055,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
if (isIncrementalGCInProgress() && !atomsZone->isCollecting())
|
||||
session.maybeLock.reset();
|
||||
|
||||
AutoGCSlice slice(rt);
|
||||
AutoDisableBarriers disableBarriers(rt);
|
||||
|
||||
bool destroyingRuntime = (reason == JS::gcreason::DESTROY_RUNTIME);
|
||||
|
||||
|
@ -7069,6 +7072,14 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
bool useZeal = false;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
char budgetBuffer[32];
|
||||
budget.describe(budgetBuffer, 32);
|
||||
stats().writeLogMessage("Incremental: %d, useZeal: %d, budget: %s",
|
||||
bool(isIncremental), bool(useZeal), budgetBuffer);
|
||||
}
|
||||
#endif
|
||||
MOZ_ASSERT_IF(isIncrementalGCInProgress(), isIncremental);
|
||||
if (isIncrementalGCInProgress() && budget.isUnlimited())
|
||||
changeToNonIncrementalGC();
|
||||
|
@ -7080,6 +7091,8 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
* Yields between slices occurs at predetermined points in these modes;
|
||||
* the budget is not used.
|
||||
*/
|
||||
stats().writeLogMessage(
|
||||
"Using unlimited budget for two-slice zeal mode");
|
||||
budget.makeUnlimited();
|
||||
}
|
||||
|
||||
|
@ -7127,7 +7140,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
MOZ_ASSERT(marker.isDrained());
|
||||
|
||||
/*
|
||||
* In incremental GCs where we have already performed more than once
|
||||
* In incremental GCs where we have already performed more than one
|
||||
* slice we yield after marking with the aim of starting the sweep in
|
||||
* the next slice, since the first slice of sweeping can be expensive.
|
||||
*
|
||||
|
@ -7144,6 +7157,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
(useZeal && hasZealMode(ZealMode::YieldBeforeSweeping))))
|
||||
{
|
||||
lastMarkSlice = true;
|
||||
stats().writeLogMessage("Yeilding before starting sweeping");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -7619,6 +7633,9 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
|
|||
if (!checkIfGCAllowedInCurrentState(reason))
|
||||
return;
|
||||
|
||||
stats().writeLogMessage("GC starting in state %s",
|
||||
StateName(incrementalState));
|
||||
|
||||
AutoTraceLog logGC(TraceLoggerForCurrentThread(), TraceLogger_GC);
|
||||
AutoStopVerifyingBarriers av(rt, IsShutdownGC(reason));
|
||||
AutoEnqueuePendingParseTasksAfterGC aept(*this);
|
||||
|
@ -7630,6 +7647,7 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
|
|||
|
||||
if (reason == JS::gcreason::ABORT_GC) {
|
||||
MOZ_ASSERT(!isIncrementalGCInProgress());
|
||||
stats().writeLogMessage("GC aborted by request");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -7669,6 +7687,7 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
|
|||
MOZ_RELEASE_ASSERT(CheckGrayMarkingState(rt));
|
||||
}
|
||||
#endif
|
||||
stats().writeLogMessage("GC ending");
|
||||
}
|
||||
|
||||
js::AutoEnqueuePendingParseTasksAfterGC::~AutoEnqueuePendingParseTasksAfterGC()
|
||||
|
|
|
@ -97,6 +97,30 @@ js::gcstats::ExplainAbortReason(gc::AbortReason reason)
|
|||
}
|
||||
}
|
||||
|
||||
static FILE*
|
||||
MaybeOpenFileFromEnv(const char* env)
|
||||
{
|
||||
FILE *file;
|
||||
const char* value = getenv(env);
|
||||
|
||||
if (!value)
|
||||
return nullptr;
|
||||
|
||||
if (strcmp(value, "none") == 0) {
|
||||
file = nullptr;
|
||||
} else if (strcmp(value, "stdout") == 0) {
|
||||
file = stdout;
|
||||
} else if (strcmp(value, "stderr") == 0) {
|
||||
file = stderr;
|
||||
} else {
|
||||
file = fopen(value, "a");
|
||||
if (!file)
|
||||
MOZ_CRASH("Failed to open log file.");
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
struct PhaseKindInfo
|
||||
{
|
||||
Phase firstPhase;
|
||||
|
@ -551,6 +575,24 @@ Statistics::renderNurseryJson(JSRuntime* rt) const
|
|||
return UniqueChars(printer.release());
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
Statistics::writeLogMessage(const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
if (gcDebugFile) {
|
||||
TimeDuration sinceStart = TimeStamp::Now() -
|
||||
TimeStamp::ProcessCreation();
|
||||
fprintf(gcDebugFile, "%12.3f: ", sinceStart.ToMicroseconds());
|
||||
vfprintf(gcDebugFile, fmt, args);
|
||||
fprintf(gcDebugFile, "\n");
|
||||
fflush(gcDebugFile);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
UniqueChars
|
||||
Statistics::renderJsonMessage(uint64_t timestamp, bool includeSlices) const
|
||||
{
|
||||
|
@ -695,7 +737,8 @@ Statistics::formatJsonPhaseTimes(const PhaseTimeTable& phaseTimes, JSONPrinter&
|
|||
|
||||
Statistics::Statistics(JSRuntime* rt)
|
||||
: runtime(rt),
|
||||
fp(nullptr),
|
||||
gcTimerFile(nullptr),
|
||||
gcDebugFile(nullptr),
|
||||
nonincrementalReason_(gc::AbortReason::None),
|
||||
preBytes(0),
|
||||
thresholdTriggered(false),
|
||||
|
@ -734,22 +777,10 @@ Statistics::Statistics(JSRuntime* rt)
|
|||
MOZ_ALWAYS_TRUE(phaseStack.reserve(MAX_PHASE_NESTING));
|
||||
MOZ_ALWAYS_TRUE(suspendedPhases.reserve(MAX_SUSPENDED_PHASES));
|
||||
|
||||
const char* env = getenv("MOZ_GCTIMER");
|
||||
if (env) {
|
||||
if (strcmp(env, "none") == 0) {
|
||||
fp = nullptr;
|
||||
} else if (strcmp(env, "stdout") == 0) {
|
||||
fp = stdout;
|
||||
} else if (strcmp(env, "stderr") == 0) {
|
||||
fp = stderr;
|
||||
} else {
|
||||
fp = fopen(env, "a");
|
||||
if (!fp)
|
||||
MOZ_CRASH("Failed to open MOZ_GCTIMER log file.");
|
||||
}
|
||||
}
|
||||
gcTimerFile = MaybeOpenFileFromEnv("MOZ_GCTIMER");
|
||||
gcDebugFile = MaybeOpenFileFromEnv("JS_GC_DEBUG");
|
||||
|
||||
env = getenv("JS_GC_PROFILE");
|
||||
const char* env = getenv("JS_GC_PROFILE");
|
||||
if (env) {
|
||||
if (0 == strcmp(env, "help")) {
|
||||
fprintf(stderr, "JS_GC_PROFILE=N\n"
|
||||
|
@ -763,8 +794,10 @@ Statistics::Statistics(JSRuntime* rt)
|
|||
|
||||
Statistics::~Statistics()
|
||||
{
|
||||
if (fp && fp != stdout && fp != stderr)
|
||||
fclose(fp);
|
||||
if (gcTimerFile && gcTimerFile != stdout && gcTimerFile != stderr)
|
||||
fclose(gcTimerFile);
|
||||
if (gcDebugFile && gcDebugFile != stdout && gcDebugFile != stderr)
|
||||
fclose(gcDebugFile);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
@ -918,16 +951,16 @@ void
|
|||
Statistics::printStats()
|
||||
{
|
||||
if (aborted) {
|
||||
fprintf(fp, "OOM during GC statistics collection. The report is unavailable for this GC.\n");
|
||||
fprintf(gcTimerFile, "OOM during GC statistics collection. The report is unavailable for this GC.\n");
|
||||
} else {
|
||||
UniqueChars msg = formatDetailedMessage();
|
||||
if (msg) {
|
||||
double secSinceStart =
|
||||
(slices_[0].start - TimeStamp::ProcessCreation()).ToSeconds();
|
||||
fprintf(fp, "GC(T+%.3fs) %s\n", secSinceStart, msg.get());
|
||||
fprintf(gcTimerFile, "GC(T+%.3fs) %s\n", secSinceStart, msg.get());
|
||||
}
|
||||
}
|
||||
fflush(fp);
|
||||
fflush(gcTimerFile);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1035,6 +1068,8 @@ Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
|
|||
(*sliceCallback)(cx, JS::GC_CYCLE_BEGIN, desc);
|
||||
(*sliceCallback)(cx, JS::GC_SLICE_BEGIN, desc);
|
||||
}
|
||||
|
||||
writeLogMessage("begin slice");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1049,6 +1084,7 @@ Statistics::endSlice()
|
|||
slice.endFaults = GetPageFaultCount();
|
||||
slice.finalState = runtime->gc.state();
|
||||
|
||||
writeLogMessage("end slice");
|
||||
TimeDuration sliceTime = slice.end - slice.start;
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_SLICE_MS, t(sliceTime));
|
||||
runtime->addTelemetry(JS_TELEMETRY_GC_RESET, slice.wasReset());
|
||||
|
@ -1086,7 +1122,7 @@ Statistics::endSlice()
|
|||
|
||||
bool last = !runtime->gc.isIncrementalGCInProgress();
|
||||
if (last) {
|
||||
if (fp)
|
||||
if (gcTimerFile)
|
||||
printStats();
|
||||
|
||||
if (!aborted)
|
||||
|
@ -1250,6 +1286,7 @@ Statistics::recordPhaseBegin(Phase phase)
|
|||
|
||||
phaseStack.infallibleAppend(phase);
|
||||
phaseStartTimes[phase] = now;
|
||||
writeLogMessage("begin: %s", phases[phase].path);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1299,6 +1336,7 @@ Statistics::recordPhaseEnd(Phase phase)
|
|||
|
||||
#ifdef DEBUG
|
||||
phaseEndTimes[phase] = now;
|
||||
writeLogMessage("end: %s", phases[phase].path);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -166,6 +166,8 @@ struct Statistics
|
|||
void nonincremental(gc::AbortReason reason) {
|
||||
MOZ_ASSERT(reason != gc::AbortReason::None);
|
||||
nonincrementalReason_ = reason;
|
||||
writeLogMessage("Non-incremental reason: %s",
|
||||
nonincrementalReason());
|
||||
}
|
||||
|
||||
bool nonincremental() const {
|
||||
|
@ -266,11 +268,21 @@ struct Statistics
|
|||
// Return JSON for the previous nursery collection.
|
||||
UniqueChars renderNurseryJson(JSRuntime* rt) const;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Print a logging message.
|
||||
void writeLogMessage(const char* fmt, ...);
|
||||
#else
|
||||
void writeLogMessage(const char* fmt, ...) { };
|
||||
#endif
|
||||
|
||||
private:
|
||||
JSRuntime* runtime;
|
||||
|
||||
/* File pointer used for MOZ_GCTIMER output. */
|
||||
FILE* fp;
|
||||
/* File used for MOZ_GCTIMER output. */
|
||||
FILE* gcTimerFile;
|
||||
|
||||
/* File used for JS_GC_DEBUG output. */
|
||||
FILE* gcDebugFile;
|
||||
|
||||
ZoneGCStats zoneStats;
|
||||
|
||||
|
|
|
@ -113,13 +113,84 @@ function checkMiscPrefixed(opcode, expect_failure) {
|
|||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// Verification cases for memory.copy/fill
|
||||
// Verification cases for memory.copy/fill opcode encodings
|
||||
|
||||
checkMiscPrefixed(0x3f, true); // unassigned
|
||||
checkMiscPrefixed(0x40, false); // memory.copy
|
||||
checkMiscPrefixed(0x41, false); // memory.fill
|
||||
checkMiscPrefixed(0x42, true); // unassigned
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// Verification cases for memory.copy/fill arguments
|
||||
|
||||
// Invalid argument types
|
||||
{
|
||||
const tys = ['i32', 'f32', 'i64', 'f64'];
|
||||
const ops = ['copy', 'fill'];
|
||||
for (let ty1 of tys) {
|
||||
for (let ty2 of tys) {
|
||||
for (let ty3 of tys) {
|
||||
for (let op of ops) {
|
||||
if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
|
||||
continue; // this is the only valid case
|
||||
let text =
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.${op} (${ty1}.const 10) (${ty2}.const 20) (${ty3}.const 30))
|
||||
)
|
||||
)`;
|
||||
assertErrorMessage(() => wasmEvalText(text),
|
||||
WebAssembly.CompileError, /type mismatch/);
|
||||
}}}}
|
||||
}
|
||||
|
||||
// Not enough, or too many, args
|
||||
{
|
||||
for (let op of ['copy', 'fill']) {
|
||||
let text1 =
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(i32.const 10)
|
||||
(i32.const 20)
|
||||
memory.${op}
|
||||
)
|
||||
)`;
|
||||
assertErrorMessage(() => wasmEvalText(text1),
|
||||
WebAssembly.CompileError,
|
||||
/popping value from empty stack/);
|
||||
let text2 =
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(i32.const 10)
|
||||
(i32.const 20)
|
||||
(i32.const 30)
|
||||
(i32.const 40)
|
||||
memory.${op}
|
||||
)
|
||||
)`;
|
||||
assertErrorMessage(() => wasmEvalText(text2),
|
||||
WebAssembly.CompileError,
|
||||
/unused values not explicitly dropped by end of block/);
|
||||
}
|
||||
}
|
||||
|
||||
// Module doesn't have a memory
|
||||
{
|
||||
for (let op of ['copy', 'fill']) {
|
||||
let text =
|
||||
`(module
|
||||
(func (export "testfn")
|
||||
(memory.${op} (i32.const 10) (i32.const 20) (i32.const 30))
|
||||
)
|
||||
)`;
|
||||
assertErrorMessage(() => wasmEvalText(text),
|
||||
WebAssembly.CompileError,
|
||||
/can't touch memory without memory/);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------//
|
||||
//---------------------------------------------------------------------//
|
||||
|
@ -139,14 +210,14 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
|
||||
// Range valid
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 256))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
inst.exports.testfn();
|
||||
let b = new Uint8Array(inst.exports.memory.buffer);
|
||||
checkRange(b, 0x00000, 0x0FF00, 0x00);
|
||||
|
@ -155,42 +226,42 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
|
||||
// Range invalid
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
||||
// Wraparound the end of 32-bit offset space
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
||||
// Zero len with offset in-bounds is a no-op
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
inst.exports.testfn();
|
||||
let b = new Uint8Array(inst.exports.memory.buffer);
|
||||
checkRange(b, 0x00000, 0x10000, 0x00);
|
||||
|
@ -198,28 +269,28 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
|
||||
// Zero len with offset out-of-bounds gets an exception
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
||||
// Very large range
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
inst.exports.testfn();
|
||||
let b = new Uint8Array(inst.exports.memory.buffer);
|
||||
checkRange(b, 0x00000, 0x00001, 0x00);
|
||||
|
@ -229,7 +300,7 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
|
||||
// Sequencing
|
||||
{
|
||||
let i = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let i = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn") (result i32)
|
||||
|
@ -238,7 +309,7 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
i32.const 99
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
i.exports.testfn();
|
||||
let b = new Uint8Array(i.exports.memory.buffer);
|
||||
checkRange(b, 0x0, 0x12+0, 0x00);
|
||||
|
@ -255,7 +326,7 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
// Both ranges valid. Copy 5 bytes backwards by 1 (overlapping).
|
||||
// result = 0x00--(09) 0x55--(11) 0x00--(pagesize-20)
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
|
@ -263,7 +334,7 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
(memory.copy (i32.const 9) (i32.const 10) (i32.const 5))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
inst.exports.testfn();
|
||||
let b = new Uint8Array(inst.exports.memory.buffer);
|
||||
checkRange(b, 0, 0+9, 0x00);
|
||||
|
@ -274,7 +345,7 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
// Both ranges valid. Copy 5 bytes forwards by 1 (overlapping).
|
||||
// result = 0x00--(10) 0x55--(11) 0x00--(pagesize-19)
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
|
@ -282,7 +353,7 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
(memory.copy (i32.const 16) (i32.const 15) (i32.const 5))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
inst.exports.testfn();
|
||||
let b = new Uint8Array(inst.exports.memory.buffer);
|
||||
checkRange(b, 0, 0+10, 0x00);
|
||||
|
@ -292,63 +363,63 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
|
||||
// Destination range invalid
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.copy (i32.const 0xFF00) (i32.const 0x8000) (i32.const 257))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
||||
// Destination wraparound the end of 32-bit offset space
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
||||
// Source range invalid
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
||||
// Source wraparound the end of 32-bit offset space
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
||||
// Zero len with both offsets in-bounds is a no-op
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
|
@ -357,7 +428,7 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
(memory.copy (i32.const 0x9000) (i32.const 0x7000) (i32.const 0))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
inst.exports.testfn();
|
||||
let b = new Uint8Array(inst.exports.memory.buffer);
|
||||
checkRange(b, 0x00000, 0x08000, 0x55);
|
||||
|
@ -366,28 +437,28 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
|
||||
// Zero len with dest offset out-of-bounds is an exception
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
||||
// Zero len with src offset out-of-bounds is an exception
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
@ -395,7 +466,7 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
// 100 random fills followed by 100 random copies, in a single-page buffer,
|
||||
// followed by verification of the (now heavily mashed-around) buffer.
|
||||
{
|
||||
let inst = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
|
@ -601,7 +672,7 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
(memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406))
|
||||
)
|
||||
)`
|
||||
)));
|
||||
);
|
||||
inst.exports.testfn();
|
||||
let b = new Uint8Array(inst.exports.memory.buffer);
|
||||
checkRange(b, 0, 124, 0);
|
||||
|
|
|
@ -4409,6 +4409,16 @@ nsDisplayTableBackgroundImage::nsDisplayTableBackgroundImage(nsDisplayListBuilde
|
|||
, mStyleFrame(aCellFrame)
|
||||
, mTableType(GetTableTypeFromFrame(mStyleFrame))
|
||||
{
|
||||
if (aBuilder->IsRetainingDisplayList()) {
|
||||
mStyleFrame->AddDisplayItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayTableBackgroundImage::~nsDisplayTableBackgroundImage()
|
||||
{
|
||||
if (mStyleFrame) {
|
||||
mStyleFrame->RemoveDisplayItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -7461,6 +7471,9 @@ nsDisplayTableFixedPosition::nsDisplayTableFixedPosition(nsDisplayListBuilder* a
|
|||
, mAncestorFrame(aAncestorFrame)
|
||||
, mTableType(GetTableTypeFromFrame(aAncestorFrame))
|
||||
{
|
||||
if (aBuilder->IsRetainingDisplayList()) {
|
||||
mAncestorFrame->AddDisplayItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ nsDisplayTableFixedPosition*
|
||||
|
|
|
@ -4226,6 +4226,7 @@ TableType GetTableTypeFromFrame(nsIFrame* aFrame);
|
|||
class nsDisplayTableBackgroundImage : public nsDisplayBackgroundImage {
|
||||
public:
|
||||
nsDisplayTableBackgroundImage(nsDisplayListBuilder* aBuilder, const InitData& aInitData, nsIFrame* aCellFrame);
|
||||
~nsDisplayTableBackgroundImage();
|
||||
|
||||
virtual uint32_t GetPerFrameKey() const override {
|
||||
return (mLayer << (TYPE_BITS + static_cast<uint8_t>(TableTypeBits::COUNT))) |
|
||||
|
@ -4237,6 +4238,17 @@ public:
|
|||
|
||||
virtual nsIFrame* FrameForInvalidation() const override { return mStyleFrame; }
|
||||
|
||||
virtual bool HasDeletedFrame() const override {
|
||||
return !mStyleFrame || nsDisplayBackgroundImage::HasDeletedFrame();
|
||||
}
|
||||
|
||||
virtual void RemoveFrame(nsIFrame* aFrame) override {
|
||||
if (aFrame == mStyleFrame) {
|
||||
mStyleFrame = nullptr;
|
||||
}
|
||||
nsDisplayBackgroundImage::RemoveFrame(aFrame);
|
||||
}
|
||||
|
||||
NS_DISPLAY_DECL_NAME("TableBackgroundImage", TYPE_TABLE_BACKGROUND_IMAGE)
|
||||
protected:
|
||||
virtual nsIFrame* StyleFrame() const override { return mStyleFrame; }
|
||||
|
@ -4324,7 +4336,16 @@ public:
|
|||
: nsDisplayThemedBackground(aBuilder, aFrame, aBackgroundRect)
|
||||
, mAncestorFrame(aAncestorFrame)
|
||||
, mTableType(GetTableTypeFromFrame(aAncestorFrame))
|
||||
{ }
|
||||
{
|
||||
if (aBuilder->IsRetainingDisplayList()) {
|
||||
mAncestorFrame->AddDisplayItem(this);
|
||||
}
|
||||
}
|
||||
~nsDisplayTableThemedBackground() {
|
||||
if (mAncestorFrame) {
|
||||
mAncestorFrame->RemoveDisplayItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
virtual uint32_t GetPerFrameKey() const override {
|
||||
return (static_cast<uint8_t>(mTableType) << TYPE_BITS) |
|
||||
|
@ -4333,6 +4354,17 @@ public:
|
|||
|
||||
virtual nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
|
||||
|
||||
virtual bool HasDeletedFrame() const override {
|
||||
return !mAncestorFrame || nsDisplayThemedBackground::HasDeletedFrame();
|
||||
}
|
||||
|
||||
virtual void RemoveFrame(nsIFrame* aFrame) override {
|
||||
if (aFrame == mAncestorFrame) {
|
||||
mAncestorFrame = nullptr;
|
||||
}
|
||||
nsDisplayThemedBackground::RemoveFrame(aFrame);
|
||||
}
|
||||
|
||||
NS_DISPLAY_DECL_NAME("TableThemedBackground", TYPE_TABLE_THEMED_BACKGROUND_IMAGE)
|
||||
protected:
|
||||
virtual nsIFrame* StyleFrame() const override { return mAncestorFrame; }
|
||||
|
@ -4467,10 +4499,30 @@ public:
|
|||
: nsDisplayBackgroundColor(aBuilder, aFrame, aBackgroundRect, aBackgroundStyle, aColor)
|
||||
, mAncestorFrame(aAncestorFrame)
|
||||
, mTableType(GetTableTypeFromFrame(aAncestorFrame))
|
||||
{ }
|
||||
{
|
||||
if (aBuilder->IsRetainingDisplayList()) {
|
||||
mAncestorFrame->AddDisplayItem(this);
|
||||
}
|
||||
}
|
||||
~nsDisplayTableBackgroundColor() {
|
||||
if (mAncestorFrame) {
|
||||
mAncestorFrame->RemoveDisplayItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
virtual nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
|
||||
|
||||
virtual bool HasDeletedFrame() const override {
|
||||
return !mAncestorFrame || nsDisplayBackgroundColor::HasDeletedFrame();
|
||||
}
|
||||
|
||||
virtual void RemoveFrame(nsIFrame* aFrame) override {
|
||||
if (aFrame == mAncestorFrame) {
|
||||
mAncestorFrame = nullptr;
|
||||
}
|
||||
nsDisplayBackgroundColor::RemoveFrame(aFrame);
|
||||
}
|
||||
|
||||
virtual uint32_t GetPerFrameKey() const override {
|
||||
return (static_cast<uint8_t>(mTableType) << TYPE_BITS) |
|
||||
nsDisplayItem::GetPerFrameKey();
|
||||
|
@ -5459,14 +5511,27 @@ public:
|
|||
: nsDisplayBlendMode(aBuilder, aFrame, aList, aBlendMode, aActiveScrolledRoot, aIndex)
|
||||
, mAncestorFrame(aAncestorFrame)
|
||||
, mTableType(GetTableTypeFromFrame(aAncestorFrame))
|
||||
{}
|
||||
{
|
||||
if (aBuilder->IsRetainingDisplayList()) {
|
||||
mAncestorFrame->AddDisplayItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayTableBlendMode(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayTableBlendMode& aOther)
|
||||
: nsDisplayBlendMode(aBuilder, aOther)
|
||||
, mAncestorFrame(aOther.mAncestorFrame)
|
||||
, mTableType(aOther.mTableType)
|
||||
{}
|
||||
{
|
||||
if (aBuilder->IsRetainingDisplayList()) {
|
||||
mAncestorFrame->AddDisplayItem(this);
|
||||
}
|
||||
}
|
||||
~nsDisplayTableBlendMode() {
|
||||
if (mAncestorFrame) {
|
||||
mAncestorFrame->RemoveDisplayItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
virtual nsDisplayWrapList* Clone(nsDisplayListBuilder* aBuilder) const override
|
||||
{
|
||||
|
@ -5475,6 +5540,17 @@ public:
|
|||
|
||||
virtual nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
|
||||
|
||||
virtual bool HasDeletedFrame() const override {
|
||||
return !mAncestorFrame || nsDisplayBlendMode::HasDeletedFrame();
|
||||
}
|
||||
|
||||
virtual void RemoveFrame(nsIFrame* aFrame) override {
|
||||
if (aFrame == mAncestorFrame) {
|
||||
mAncestorFrame = nullptr;
|
||||
}
|
||||
nsDisplayBlendMode::RemoveFrame(aFrame);
|
||||
}
|
||||
|
||||
virtual uint32_t GetPerFrameKey() const override {
|
||||
return (mIndex << (TYPE_BITS + static_cast<uint8_t>(TableTypeBits::COUNT))) |
|
||||
(static_cast<uint8_t>(mTableType) << TYPE_BITS) |
|
||||
|
@ -5571,6 +5647,17 @@ public:
|
|||
|
||||
virtual nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
|
||||
|
||||
virtual bool HasDeletedFrame() const override {
|
||||
return !mAncestorFrame || nsDisplayBlendContainer::HasDeletedFrame();
|
||||
}
|
||||
|
||||
virtual void RemoveFrame(nsIFrame* aFrame) override {
|
||||
if (aFrame == mAncestorFrame) {
|
||||
mAncestorFrame = nullptr;
|
||||
}
|
||||
nsDisplayBlendContainer::RemoveFrame(aFrame);
|
||||
}
|
||||
|
||||
virtual uint32_t GetPerFrameKey() const override {
|
||||
return (static_cast<uint8_t>(mTableType) << TYPE_BITS) |
|
||||
nsDisplayItem::GetPerFrameKey();
|
||||
|
@ -5586,14 +5673,27 @@ protected:
|
|||
: nsDisplayBlendContainer(aBuilder, aFrame, aList, aActiveScrolledRoot, aIsForBackground)
|
||||
, mAncestorFrame(aAncestorFrame)
|
||||
, mTableType(GetTableTypeFromFrame(aAncestorFrame))
|
||||
{}
|
||||
{
|
||||
if (aBuilder->IsRetainingDisplayList()) {
|
||||
mAncestorFrame->AddDisplayItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayTableBlendContainer(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayTableBlendContainer& aOther)
|
||||
: nsDisplayBlendContainer(aBuilder, aOther)
|
||||
, mAncestorFrame(aOther.mAncestorFrame)
|
||||
, mTableType(aOther.mTableType)
|
||||
{}
|
||||
{
|
||||
if (aBuilder->IsRetainingDisplayList()) {
|
||||
mAncestorFrame->AddDisplayItem(this);
|
||||
}
|
||||
}
|
||||
~nsDisplayTableBlendContainer() {
|
||||
if (mAncestorFrame) {
|
||||
mAncestorFrame->RemoveDisplayItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame* mAncestorFrame;
|
||||
TableType mTableType;
|
||||
|
@ -5939,6 +6039,17 @@ public:
|
|||
|
||||
virtual nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
|
||||
|
||||
virtual bool HasDeletedFrame() const override {
|
||||
return !mAncestorFrame || nsDisplayFixedPosition::HasDeletedFrame();
|
||||
}
|
||||
|
||||
virtual void RemoveFrame(nsIFrame* aFrame) override {
|
||||
if (aFrame == mAncestorFrame) {
|
||||
mAncestorFrame = nullptr;
|
||||
}
|
||||
nsDisplayFixedPosition::RemoveFrame(aFrame);
|
||||
}
|
||||
|
||||
virtual uint32_t GetPerFrameKey() const override {
|
||||
return (mIndex << (TYPE_BITS + static_cast<uint8_t>(TableTypeBits::COUNT))) |
|
||||
(static_cast<uint8_t>(mTableType) << TYPE_BITS) |
|
||||
|
@ -5956,7 +6067,16 @@ protected:
|
|||
: nsDisplayFixedPosition(aBuilder, aOther)
|
||||
, mAncestorFrame(aOther.mAncestorFrame)
|
||||
, mTableType(aOther.mTableType)
|
||||
{}
|
||||
{
|
||||
if (aBuilder->IsRetainingDisplayList()) {
|
||||
mAncestorFrame->AddDisplayItem(this);
|
||||
}
|
||||
}
|
||||
~nsDisplayTableFixedPosition() {
|
||||
if (mAncestorFrame) {
|
||||
mAncestorFrame->RemoveDisplayItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame* mAncestorFrame;
|
||||
TableType mTableType;
|
||||
|
|
|
@ -1196,9 +1196,9 @@ fuzzy-if(webrender,4,361) == 449519-1.html 449519-1-ref.html
|
|||
== 455280-1.xhtml 455280-1-ref.xhtml
|
||||
== 455826-1.html 455826-1-ref.html
|
||||
fails-if(Android||cocoaWidget||winWidget) == 456147.xul 456147-ref.html # bug 458047
|
||||
fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,15,69) fuzzy-if(skiaContent,42,154) fuzzy-if(webrender,56-60,450-497) == 456219-1a.html 456219-1-ref.html # bug 1128229
|
||||
fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,15,69) fuzzy-if(skiaContent,42,154) fuzzy-if(webrender,56-60,450-497) == 456219-1b.html 456219-1-ref.html # bug 1128229
|
||||
fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,15,69) fuzzy-if(skiaContent,42,154) fuzzy-if(webrender,56-60,450-497) == 456219-1c.html 456219-1-ref.html # bug 1128229
|
||||
fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,15,69) fuzzy-if(skiaContent,42,154) fuzzy-if(webrender,56-60,449-497) == 456219-1a.html 456219-1-ref.html # bug 1128229
|
||||
fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,15,69) fuzzy-if(skiaContent,42,154) fuzzy-if(webrender,56-60,449-497) == 456219-1b.html 456219-1-ref.html # bug 1128229
|
||||
fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,15,69) fuzzy-if(skiaContent,42,154) fuzzy-if(webrender,56-60,449-497) == 456219-1c.html 456219-1-ref.html # bug 1128229
|
||||
fuzzy-if(skiaContent,1,45) fuzzy-if(webrender,9-9,8-8) == 456219-2.html 456219-2-ref.html
|
||||
== 456330-1.gif 456330-1-ref.png
|
||||
== 456484-1.html 456484-1-ref.html
|
||||
|
|
|
@ -1,62 +1,62 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Reftest Reference</title>
|
||||
<link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
|
||||
<style>
|
||||
div {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
}
|
||||
#div1,
|
||||
#div3 {
|
||||
background-color: #cfc;
|
||||
}
|
||||
#div1 {
|
||||
z-index: 5;
|
||||
}
|
||||
#div2 {
|
||||
z-index: 1;
|
||||
background-color: #fdd;
|
||||
height: 100px;
|
||||
top: -20px;
|
||||
}
|
||||
#div2_1 {
|
||||
background-color: #ffc;
|
||||
z-index: 6;
|
||||
top: -10px;
|
||||
}
|
||||
#div2_2 {
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
width: 40px;
|
||||
height: 100px;
|
||||
background-color: #ddf;
|
||||
}
|
||||
#div3 {
|
||||
z-index: 2;
|
||||
top: -50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="div1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2">
|
||||
<div id="div2_1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2_2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="div3">
|
||||
<br/><br/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Reftest Reference</title>
|
||||
<link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
|
||||
<style>
|
||||
div {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
}
|
||||
#div1,
|
||||
#div3 {
|
||||
background-color: #cfc;
|
||||
}
|
||||
#div1 {
|
||||
z-index: 5;
|
||||
}
|
||||
#div2 {
|
||||
z-index: 1;
|
||||
background-color: #fdd;
|
||||
height: 100px;
|
||||
top: -20px;
|
||||
}
|
||||
#div2_1 {
|
||||
background-color: #ffc;
|
||||
z-index: 6;
|
||||
top: -10px;
|
||||
}
|
||||
#div2_2 {
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
width: 40px;
|
||||
height: 100px;
|
||||
background-color: #ddf;
|
||||
}
|
||||
#div3 {
|
||||
z-index: 2;
|
||||
top: -50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="div1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2">
|
||||
<div id="div2_1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2_2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="div3">
|
||||
<br/><br/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,66 +1,66 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Test: 'contain: paint' with stacking contents. Z-index is defined only for siblings and children.</title>
|
||||
<link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
|
||||
|
||||
<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#x43">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
|
||||
<link rel="match" href="contain-paint-stacking-context-001-ref.html">
|
||||
<style>
|
||||
div {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
}
|
||||
#div1,
|
||||
#div3 {
|
||||
background-color: #cfc;
|
||||
}
|
||||
#div1 {
|
||||
z-index: 5;
|
||||
}
|
||||
#div2 {
|
||||
contain: paint;
|
||||
background-color: #fdd;
|
||||
height: 100px;
|
||||
top: -20px;
|
||||
}
|
||||
#div2_1 {
|
||||
background-color: #ffc;
|
||||
z-index: 6;
|
||||
top: -10px;
|
||||
}
|
||||
#div2_2 {
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
width: 40px;
|
||||
height: 100px;
|
||||
background-color: #ddf;
|
||||
}
|
||||
#div3 {
|
||||
z-index: 2;
|
||||
top: -50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="div1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2">
|
||||
<div id="div2_1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2_2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="div3">
|
||||
<br/><br/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Test: 'contain: paint' with stacking contents. Z-index is defined only for siblings and children.</title>
|
||||
<link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
|
||||
|
||||
<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#x43">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
|
||||
<link rel="match" href="contain-paint-stacking-context-001-ref.html">
|
||||
<style>
|
||||
div {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
}
|
||||
#div1,
|
||||
#div3 {
|
||||
background-color: #cfc;
|
||||
}
|
||||
#div1 {
|
||||
z-index: 5;
|
||||
}
|
||||
#div2 {
|
||||
contain: paint;
|
||||
background-color: #fdd;
|
||||
height: 100px;
|
||||
top: -20px;
|
||||
}
|
||||
#div2_1 {
|
||||
background-color: #ffc;
|
||||
z-index: 6;
|
||||
top: -10px;
|
||||
}
|
||||
#div2_2 {
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
width: 40px;
|
||||
height: 100px;
|
||||
background-color: #ddf;
|
||||
}
|
||||
#div3 {
|
||||
z-index: 2;
|
||||
top: -50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="div1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2">
|
||||
<div id="div2_1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2_2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="div3">
|
||||
<br/><br/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,66 +1,66 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Test: 'will-change: contain' with stacking contents. Z-index is defined only for siblings and children.</title>
|
||||
<link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
|
||||
|
||||
<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#x43">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
|
||||
<link rel="match" href="contain-paint-stacking-context-001-ref.html">
|
||||
<style>
|
||||
div {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
}
|
||||
#div1,
|
||||
#div3 {
|
||||
background-color: #cfc;
|
||||
}
|
||||
#div1 {
|
||||
z-index: 5;
|
||||
}
|
||||
#div2 {
|
||||
will-change: contain;
|
||||
background-color: #fdd;
|
||||
height: 100px;
|
||||
top: -20px;
|
||||
}
|
||||
#div2_1 {
|
||||
background-color: #ffc;
|
||||
z-index: 6;
|
||||
top: -10px;
|
||||
}
|
||||
#div2_2 {
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
width: 40px;
|
||||
height: 100px;
|
||||
background-color: #ddf;
|
||||
}
|
||||
#div3 {
|
||||
z-index: 2;
|
||||
top: -50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="div1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2">
|
||||
<div id="div2_1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2_2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="div3">
|
||||
<br/><br/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Test: 'will-change: contain' with stacking contents. Z-index is defined only for siblings and children.</title>
|
||||
<link rel="author" title="Yusuf Sermet" href="mailto:ysermet@mozilla.com">
|
||||
|
||||
<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#x43">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-contain/#containment-paint">
|
||||
<link rel="match" href="contain-paint-stacking-context-001-ref.html">
|
||||
<style>
|
||||
div {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
}
|
||||
#div1,
|
||||
#div3 {
|
||||
background-color: #cfc;
|
||||
}
|
||||
#div1 {
|
||||
z-index: 5;
|
||||
}
|
||||
#div2 {
|
||||
will-change: contain;
|
||||
background-color: #fdd;
|
||||
height: 100px;
|
||||
top: -20px;
|
||||
}
|
||||
#div2_1 {
|
||||
background-color: #ffc;
|
||||
z-index: 6;
|
||||
top: -10px;
|
||||
}
|
||||
#div2_2 {
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
width: 40px;
|
||||
height: 100px;
|
||||
background-color: #ddf;
|
||||
}
|
||||
#div3 {
|
||||
z-index: 2;
|
||||
top: -50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="div1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2">
|
||||
<div id="div2_1">
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
<div id="div2_2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="div3">
|
||||
<br/><br/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -84,67 +84,20 @@ private:
|
|||
};
|
||||
|
||||
template <typename MMPolicy, uint32_t kChunkSize>
|
||||
class VMSharingPolicyShared : public MMPolicyBase
|
||||
class VMSharingPolicyShared;
|
||||
|
||||
// We only support this policy for in-proc MMPolicy
|
||||
template <uint32_t kChunkSize>
|
||||
class VMSharingPolicyShared<MMPolicyInProcess, kChunkSize> : public MMPolicyBase
|
||||
{
|
||||
typedef VMSharingPolicyUnique<MMPolicy, kChunkSize> ValueT;
|
||||
|
||||
// We use pid instead of HANDLE for mapping, since more than one handle may
|
||||
// map to the same pid. We don't worry about pid reuse becuase each mVMPolicy
|
||||
// holds an open handle to pid, thus keeping the pid reserved at least for the
|
||||
// lifetime of mVMPolicy.
|
||||
struct ProcMapEntry
|
||||
{
|
||||
ProcMapEntry()
|
||||
: mPid(::GetCurrentProcessId())
|
||||
{
|
||||
}
|
||||
|
||||
explicit ProcMapEntry(HANDLE aProc)
|
||||
: mPid(::GetProcessId(aProc))
|
||||
, mVMPolicy(aProc)
|
||||
{
|
||||
}
|
||||
|
||||
ProcMapEntry(ProcMapEntry&& aOther)
|
||||
: mPid(aOther.mPid)
|
||||
, mVMPolicy(Move(aOther.mVMPolicy))
|
||||
{
|
||||
aOther.mPid = 0;
|
||||
}
|
||||
|
||||
ProcMapEntry(const ProcMapEntry&) = delete;
|
||||
ProcMapEntry& operator=(const ProcMapEntry&) = delete;
|
||||
|
||||
ProcMapEntry& operator=(ProcMapEntry&& aOther)
|
||||
{
|
||||
mPid = aOther.mPid;
|
||||
mVMPolicy = Move(aOther.mVMPolicy);
|
||||
aOther.mPid = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(DWORD aPid) const
|
||||
{
|
||||
return mPid == aPid;
|
||||
}
|
||||
|
||||
DWORD mPid;
|
||||
ValueT mVMPolicy;
|
||||
};
|
||||
|
||||
// We normally expect to reference only one other process at a time, but this
|
||||
// is not a requirement.
|
||||
typedef Vector<ProcMapEntry, 1> MapT;
|
||||
typedef VMSharingPolicyUnique<MMPolicyInProcess, kChunkSize> UniquePolicyT;
|
||||
|
||||
public:
|
||||
typedef MMPolicy MMPolicyT;
|
||||
typedef MMPolicyInProcess MMPolicyT;
|
||||
|
||||
template <typename... Args>
|
||||
explicit VMSharingPolicyShared(Args... aArgs)
|
||||
: mPid(GetPid(aArgs...))
|
||||
VMSharingPolicyShared()
|
||||
{
|
||||
static const bool isAlloc = []() -> bool {
|
||||
sPerProcVM = new MapT();
|
||||
DWORD flags = 0;
|
||||
#if defined(RELEASE_OR_BETA)
|
||||
flags |= CRITICAL_SECTION_NO_DEBUG_INFO;
|
||||
|
@ -152,101 +105,48 @@ public:
|
|||
::InitializeCriticalSectionEx(&sCS, 4000, flags);
|
||||
return true;
|
||||
}();
|
||||
|
||||
MOZ_ASSERT(mPid);
|
||||
if (!mPid) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoCriticalSection lock(&sCS);
|
||||
|
||||
if (find(mPid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool appended = sPerProcVM->append(ProcMapEntry(aArgs...));
|
||||
MOZ_RELEASE_ASSERT(appended);
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
AutoCriticalSection lock(&sCS);
|
||||
|
||||
ProcMapEntry* entry;
|
||||
bool found = find(mPid, &entry);
|
||||
MOZ_RELEASE_ASSERT(found);
|
||||
|
||||
return !!entry->mVMPolicy;
|
||||
return !!sUniqueVM;
|
||||
}
|
||||
|
||||
operator const MMPolicy&() const
|
||||
operator const MMPolicyInProcess&() const
|
||||
{
|
||||
AutoCriticalSection lock(&sCS);
|
||||
|
||||
ProcMapEntry* entry;
|
||||
bool found = find(mPid, &entry);
|
||||
MOZ_RELEASE_ASSERT(found);
|
||||
|
||||
return entry->mVMPolicy;
|
||||
return sUniqueVM;
|
||||
}
|
||||
|
||||
bool ShouldUnhookUponDestruction() const
|
||||
{
|
||||
AutoCriticalSection lock(&sCS);
|
||||
|
||||
ProcMapEntry* entry;
|
||||
if (!find(mPid, &entry)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return entry->mVMPolicy.ShouldUnhookUponDestruction();
|
||||
return sUniqueVM.ShouldUnhookUponDestruction();
|
||||
}
|
||||
|
||||
bool Reserve(uint32_t aCount)
|
||||
{
|
||||
AutoCriticalSection lock(&sCS);
|
||||
|
||||
ProcMapEntry* entry;
|
||||
if (!find(mPid, &entry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return entry->mVMPolicy.Reserve(aCount);
|
||||
return sUniqueVM.Reserve(aCount);
|
||||
}
|
||||
|
||||
bool IsPageAccessible(void* aVAddress) const
|
||||
{
|
||||
AutoCriticalSection lock(&sCS);
|
||||
|
||||
ProcMapEntry* entry;
|
||||
if (!find(mPid, &entry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return entry->mVMPolicy.IsPageAccessible(aVAddress);
|
||||
return sUniqueVM.IsPageAccessible(aVAddress);
|
||||
}
|
||||
|
||||
Trampoline<MMPolicy> GetNextTrampoline()
|
||||
Trampoline<MMPolicyInProcess> GetNextTrampoline()
|
||||
{
|
||||
AutoCriticalSection lock(&sCS);
|
||||
|
||||
ProcMapEntry* entry;
|
||||
if (!find(mPid, &entry)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return entry->mVMPolicy.GetNextTrampoline();
|
||||
return sUniqueVM.GetNextTrampoline();
|
||||
}
|
||||
|
||||
TrampolineCollection<MMPolicy> Items() const
|
||||
TrampolineCollection<MMPolicyInProcess> Items() const
|
||||
{
|
||||
AutoCriticalSection lock(&sCS);
|
||||
|
||||
ProcMapEntry* entry;
|
||||
bool found = find(mPid, &entry);
|
||||
MOZ_RELEASE_ASSERT(found);
|
||||
|
||||
TrampolineCollection<MMPolicy> items(Move(entry->mVMPolicy.Items()));
|
||||
TrampolineCollection<MMPolicyInProcess> items(Move(sUniqueVM.Items()));
|
||||
|
||||
// We need to continue holding the lock until items is destroyed.
|
||||
items.Lock(sCS);
|
||||
|
@ -268,43 +168,16 @@ public:
|
|||
VMSharingPolicyShared& operator=(VMSharingPolicyShared&&) = delete;
|
||||
|
||||
private:
|
||||
static bool find(DWORD aPid, ProcMapEntry** aOutEntry = nullptr)
|
||||
{
|
||||
MOZ_ASSERT(sPerProcVM);
|
||||
if (!sPerProcVM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aOutEntry) {
|
||||
*aOutEntry = nullptr;
|
||||
}
|
||||
|
||||
for (auto&& mapping : *sPerProcVM) {
|
||||
if (mapping == aPid) {
|
||||
if (aOutEntry) {
|
||||
*aOutEntry = &mapping;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static DWORD GetPid() { return ::GetCurrentProcessId(); }
|
||||
static DWORD GetPid(HANDLE aHandle) { return ::GetProcessId(aHandle); }
|
||||
|
||||
DWORD mPid;
|
||||
static MapT* sPerProcVM;
|
||||
static UniquePolicyT sUniqueVM;
|
||||
static CRITICAL_SECTION sCS;
|
||||
};
|
||||
|
||||
template <typename MMPolicy, uint32_t kChunkSize>
|
||||
typename VMSharingPolicyShared<MMPolicy, kChunkSize>::MapT *
|
||||
VMSharingPolicyShared<MMPolicy, kChunkSize>::sPerProcVM;
|
||||
template <uint32_t kChunkSize>
|
||||
typename VMSharingPolicyShared<MMPolicyInProcess, kChunkSize>::UniquePolicyT
|
||||
VMSharingPolicyShared<MMPolicyInProcess, kChunkSize>::sUniqueVM;
|
||||
|
||||
template <typename MMPolicy, uint32_t kChunkSize>
|
||||
CRITICAL_SECTION VMSharingPolicyShared<MMPolicy, kChunkSize>::sCS;
|
||||
template <uint32_t kChunkSize>
|
||||
CRITICAL_SECTION VMSharingPolicyShared<MMPolicyInProcess, kChunkSize>::sCS;
|
||||
|
||||
} // namespace interceptor
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -140,7 +140,7 @@ nsBufferedStream::Seek(int32_t whence, int64_t offset)
|
|||
nsCOMPtr<nsISeekableStream> ras = do_QueryInterface(mStream, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
#ifdef DEBUG
|
||||
NS_ERROR("mStream doesn't QI to nsISeekableStream");
|
||||
NS_WARNING("mStream doesn't QI to nsISeekableStream");
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -277,3 +277,37 @@ macosx64-nightly/opt:
|
|||
- linux64-llvm-dsymutil
|
||||
- linux64-rust-macos
|
||||
- linux64-sccache
|
||||
|
||||
macosx64-ccov/debug:
|
||||
description: "MacOS X x64 Cross-compile Code Coverage"
|
||||
index:
|
||||
product: firefox
|
||||
job-name: macosx64-ccov-debug
|
||||
treeherder:
|
||||
platform: osx-cross-ccov/debug
|
||||
symbol: B
|
||||
tier: 1
|
||||
worker-type: aws-provisioner-v1/gecko-{level}-b-macosx64
|
||||
worker:
|
||||
max-run-time: 5400
|
||||
env:
|
||||
TOOLTOOL_MANIFEST: "browser/config/tooltool-manifests/macosx64/cross-releng.manifest"
|
||||
run:
|
||||
using: mozharness
|
||||
actions: [get-secrets build update]
|
||||
config:
|
||||
- builds/releng_base_firefox.py
|
||||
- builds/releng_base_mac_64_cross_builds.py
|
||||
script: "mozharness/scripts/fx_desktop_build.py"
|
||||
secrets: true
|
||||
custom-build-variant-cfg: code-coverage-debug
|
||||
tooltool-downloads: internal
|
||||
run-on-projects: ['try']
|
||||
toolchains:
|
||||
- linux64-cctools-port
|
||||
- linux64-clang-6-pre-macosx-cross
|
||||
- linux64-hfsplus
|
||||
- linux64-libdmg
|
||||
- linux64-llvm-dsymutil
|
||||
- linux64-rust-macos
|
||||
- linux64-sccache
|
||||
|
|
|
@ -261,6 +261,11 @@ macosx64-qr/debug:
|
|||
test-sets:
|
||||
- macosx64-qr-tests
|
||||
|
||||
macosx64-ccov/debug:
|
||||
build-platform: macosx64-ccov/debug
|
||||
test-sets:
|
||||
- macosx64-tests
|
||||
|
||||
##
|
||||
# Android platforms (matching /android.*/)
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ BUILDER_NAME_PREFIX = {
|
|||
'linux64-devedition-nightly': 'Ubuntu VM 12.04 x64',
|
||||
'macosx64': 'Rev7 MacOSX Yosemite 10.10.5',
|
||||
'macosx64-devedition': 'Rev7 MacOSX Yosemite 10.10.5 DevEdition',
|
||||
'macosx64-ccov': 'Rev7 MacOSX Yosemite 10.10.5 Code Coverage',
|
||||
'android-4.3-arm7-api-16': 'Android 4.3 armv7 api-16+',
|
||||
'android-4.2-x86': 'Android 4.2 x86 Emulator',
|
||||
'android-4.3-arm7-api-16-gradle': 'Android 4.3 armv7 api-16+',
|
||||
|
|
|
@ -702,8 +702,7 @@ def handle_suite_category(config, tests):
|
|||
|
||||
@transforms.add
|
||||
def enable_code_coverage(config, tests):
|
||||
"""Enable code coverage for the linux64-ccov/.* & linux64-jsdcov/.* & win64-ccov/.*
|
||||
build-platforms"""
|
||||
"""Enable code coverage for the ccov and jsdcov build-platforms"""
|
||||
for test in tests:
|
||||
if 'ccov' in test['build-platform'] and not test['test-name'].startswith('test-verify'):
|
||||
test['mozharness'].setdefault('extra-options', []).append('--code-coverage')
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import os
|
||||
|
||||
config = {
|
||||
'default_actions': [
|
||||
'clobber',
|
||||
'build',
|
||||
'check-test',
|
||||
'update', # decided by query_is_nightly()
|
||||
],
|
||||
'stage_platform': 'macosx64-ccov-debug',
|
||||
'debug_build': True,
|
||||
#### 64 bit build specific #####
|
||||
'env': {
|
||||
'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'),
|
||||
'HG_SHARE_BASE_DIR': '/builds/hg-shared',
|
||||
'MOZ_OBJDIR': '%(abs_obj_dir)s',
|
||||
'TINDERBOX_OUTPUT': '1',
|
||||
'TOOLTOOL_CACHE': '/builds/tooltool_cache',
|
||||
'TOOLTOOL_HOME': '/builds',
|
||||
'MOZ_CRASHREPORTER_NO_REPORT': '1',
|
||||
'LC_ALL': 'C',
|
||||
## 64 bit specific
|
||||
'PATH': '/tools/python/bin:/opt/local/bin:/usr/bin:'
|
||||
'/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin',
|
||||
##
|
||||
},
|
||||
'mozconfig_variant': 'code-coverage-debug',
|
||||
#######################
|
||||
}
|
|
@ -1,3 +1,2 @@
|
|||
[label-attributes.html]
|
||||
prefs: [dom.webcomponents.shadowdom.enabled:true]
|
||||
max-asserts: 8
|
||||
|
|
|
@ -227,7 +227,8 @@
|
|||
}, "A labelable element is moved to iframe.");
|
||||
|
||||
test(function () {
|
||||
var labels1 = document.getElementById("test14").labels;
|
||||
var test14 = document.getElementById("test14");
|
||||
var labels1 = test14.labels;
|
||||
var labels2 = document.getElementById("test15").labels;
|
||||
assert_true(labels1 instanceof NodeList,
|
||||
"A form control's 'labels' property should be an instance of a NodeList.");
|
||||
|
@ -237,12 +238,17 @@
|
|||
"The number of labels associated with a form control should be the number of label elements for which it is a labeled control.");
|
||||
assert_array_equals(labels1, [document.getElementById("lbl14")],
|
||||
"The labels for a form control should be returned in tree order.");
|
||||
assert_array_equals(labels2, [document.getElementById("lbl15")],
|
||||
"The labels for a form control should be returned in tree order.");
|
||||
|
||||
document.getElementById('div6').removeChild(document.getElementById('div7'));
|
||||
assert_equals(labels1.length, 0,
|
||||
"The number of labels should be 0 after the labelable element is removed.");
|
||||
assert_equals(labels1.length, 1,
|
||||
"The number of labels should be 1 after the labelable element is removed but label element is still in the same tree.");
|
||||
assert_equals(labels2.length, 0,
|
||||
"The number of labels should be 0 since there is no label with a 'for' attribute associated with this labelable element.");
|
||||
test14.remove();
|
||||
assert_equals(labels1.length, 0,
|
||||
"The number of labels should be 0 after the labelable element is removed.");
|
||||
}, "A div element which contains labelable element is removed.");
|
||||
|
||||
test(function () {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "base/basictypes.h"
|
||||
|
||||
#include "nsMultiplexInputStream.h"
|
||||
#include "nsIBufferedStreams.h"
|
||||
#include "nsICloneableInputStream.h"
|
||||
#include "nsIMultiplexInputStream.h"
|
||||
#include "nsISeekableStream.h"
|
||||
|
@ -27,6 +28,8 @@
|
|||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIInputStreamLength.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::ipc;
|
||||
|
@ -69,11 +72,12 @@ public:
|
|||
|
||||
struct StreamData
|
||||
{
|
||||
void Initialize(nsIInputStream* aStream)
|
||||
void Initialize(nsIInputStream* aStream, bool aBuffered)
|
||||
{
|
||||
mStream = aStream;
|
||||
mAsyncStream = do_QueryInterface(aStream);
|
||||
mSeekableStream = do_QueryInterface(aStream);
|
||||
mBuffered = aBuffered;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
|
@ -82,6 +86,9 @@ public:
|
|||
nsCOMPtr<nsIAsyncInputStream> mAsyncStream;
|
||||
// This can be null.
|
||||
nsCOMPtr<nsISeekableStream> mSeekableStream;
|
||||
|
||||
// True if the stream is wrapped with nsIBufferedInputStream.
|
||||
bool mBuffered;
|
||||
};
|
||||
|
||||
Mutex& GetLock()
|
||||
|
@ -240,6 +247,18 @@ nsMultiplexInputStream::GetCount(uint32_t* aCount)
|
|||
NS_IMETHODIMP
|
||||
nsMultiplexInputStream::AppendStream(nsIInputStream* aStream)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> stream = aStream;
|
||||
|
||||
bool buffered = false;
|
||||
if (!NS_InputStreamIsBuffered(stream)) {
|
||||
nsCOMPtr<nsIInputStream> bufferedStream;
|
||||
nsresult rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
|
||||
stream.forget(), 4096);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
stream = bufferedStream.forget();
|
||||
buffered = true;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
StreamData* streamData = mStreams.AppendElement();
|
||||
|
@ -247,7 +266,7 @@ nsMultiplexInputStream::AppendStream(nsIInputStream* aStream)
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
streamData->Initialize(aStream);
|
||||
streamData->Initialize(stream, buffered);
|
||||
|
||||
UpdateQIMap(*streamData, 1);
|
||||
|
||||
|
@ -271,6 +290,17 @@ nsMultiplexInputStream::GetStream(uint32_t aIndex, nsIInputStream** aResult)
|
|||
StreamData& streamData = mStreams.ElementAt(aIndex);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream = streamData.mStream;
|
||||
|
||||
if (streamData.mBuffered) {
|
||||
nsCOMPtr<nsIBufferedInputStream> bufferedStream = do_QueryInterface(stream);
|
||||
MOZ_ASSERT(bufferedStream);
|
||||
|
||||
nsresult rv = bufferedStream->GetData(getter_AddRefs(stream));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
stream.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "nsIInputStream.h"
|
||||
#include "nsIMultiplexInputStream.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "Helpers.h"
|
||||
|
||||
|
@ -230,8 +231,7 @@ public:
|
|||
ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t *aResult) override
|
||||
{
|
||||
MOZ_CRASH("This should not be called!");
|
||||
return NS_OK;
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
|
@ -281,8 +281,7 @@ public:
|
|||
ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t *aResult) override
|
||||
{
|
||||
MOZ_CRASH("This should not be called!");
|
||||
return NS_OK;
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
|
@ -387,6 +386,90 @@ TEST(TestMultiplexInputStream, Available) {
|
|||
ASSERT_EQ(buffer.Length(), length);
|
||||
}
|
||||
|
||||
class NonBufferableStringStream final : public nsIInputStream
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
explicit NonBufferableStringStream(const nsACString& aBuffer)
|
||||
{
|
||||
NS_NewCStringInputStream(getter_AddRefs(mStream), aBuffer);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Available(uint64_t* aLength) override
|
||||
{
|
||||
return mStream->Available(aLength);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override
|
||||
{
|
||||
return mStream->Read(aBuffer, aCount, aReadCount);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t *aResult) override
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Close() override
|
||||
{
|
||||
return mStream->Close();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
IsNonBlocking(bool* aNonBlocking) override
|
||||
{
|
||||
return mStream->IsNonBlocking(aNonBlocking);
|
||||
}
|
||||
|
||||
private:
|
||||
~NonBufferableStringStream() = default;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(NonBufferableStringStream, nsIInputStream)
|
||||
|
||||
TEST(TestMultiplexInputStream, Bufferable) {
|
||||
nsCOMPtr<nsIMultiplexInputStream> multiplexStream =
|
||||
do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
|
||||
|
||||
nsCOMPtr<nsIInputStream> s = do_QueryInterface(multiplexStream);
|
||||
ASSERT_TRUE(!!s);
|
||||
|
||||
nsCString buf1;
|
||||
buf1.AssignLiteral("Hello ");
|
||||
nsCOMPtr<nsIInputStream> inputStream1;
|
||||
nsresult rv = NS_NewCStringInputStream(getter_AddRefs(inputStream1), buf1);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
nsCString buf2;
|
||||
buf2.AssignLiteral("world");
|
||||
nsCOMPtr<nsIInputStream> inputStream2 = new NonBufferableStringStream(buf2);
|
||||
|
||||
rv = multiplexStream->AppendStream(inputStream1);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
rv = multiplexStream->AppendStream(inputStream2);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream(do_QueryInterface(multiplexStream));
|
||||
ASSERT_TRUE(!!stream);
|
||||
|
||||
char buf3[1024];
|
||||
uint32_t size = 0;
|
||||
rv = stream->ReadSegments(NS_CopySegmentToBuffer, buf3, sizeof(buf3), &size);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
ASSERT_EQ(size, buf1.Length() + buf2.Length());
|
||||
ASSERT_TRUE(!strncmp(buf3, "Hello world", size));
|
||||
}
|
||||
|
||||
TEST(TestMultiplexInputStream, QILengthInputStream) {
|
||||
nsCString buf;
|
||||
buf.AssignLiteral("Hello world");
|
||||
|
|
Загрузка…
Ссылка в новой задаче