зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
1133b6716d
|
@ -60,6 +60,7 @@
|
|||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/TouchEvents.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "Units.h"
|
||||
#include "nsBrowserStatusFilter.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDocShell.h"
|
||||
|
@ -436,7 +437,7 @@ BrowserChild::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
nsCOMPtr<Document> subject(do_QueryInterface(aSubject));
|
||||
nsCOMPtr<Document> doc(GetTopLevelDocument());
|
||||
|
||||
if (subject == doc) {
|
||||
if (subject == doc && doc->IsTopLevelContentDocument()) {
|
||||
RefPtr<PresShell> presShell = doc->GetPresShell();
|
||||
if (presShell) {
|
||||
presShell->SetIsFirstPaint(true);
|
||||
|
@ -2741,7 +2742,7 @@ bool BrowserChild::IsVisible() {
|
|||
}
|
||||
|
||||
void BrowserChild::UpdateVisibility(bool aForceRepaint) {
|
||||
bool shouldBeVisible = mIsTopLevel ? mRenderLayers : mEffectsInfo.mVisible;
|
||||
bool shouldBeVisible = mIsTopLevel ? mRenderLayers : mEffectsInfo.IsVisible();
|
||||
bool isVisible = IsVisible();
|
||||
|
||||
if (shouldBeVisible != isVisible) {
|
||||
|
@ -3328,6 +3329,17 @@ ScreenIntSize BrowserChild::GetInnerSize() {
|
|||
innerSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
|
||||
};
|
||||
|
||||
nsRect BrowserChild::GetVisibleRect() {
|
||||
bool isForceRendering = mIsTopLevel && mRenderLayers;
|
||||
if (isForceRendering && !mEffectsInfo.IsVisible()) {
|
||||
// We are forced to render even though we are not visible. In this case, we
|
||||
// don't have an accurate visible rect, so we must be conservative.
|
||||
return nsRect(nsPoint(), CSSPixel::ToAppUnits(mUnscaledInnerSize));
|
||||
} else {
|
||||
return mEffectsInfo.mVisibleRect;
|
||||
}
|
||||
}
|
||||
|
||||
ScreenIntRect BrowserChild::GetOuterRect() {
|
||||
LayoutDeviceIntRect outerRect =
|
||||
RoundedToInt(mUnscaledOuterRect * mPuppetWidget->GetDefaultScale());
|
||||
|
|
|
@ -418,6 +418,8 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
|
||||
bool IsTransparent() const { return mIsTransparent; }
|
||||
|
||||
const EffectsInfo& GetEffectsInfo() const { return mEffectsInfo; }
|
||||
|
||||
void GetMaxTouchPoints(uint32_t* aTouchPoints) {
|
||||
*aTouchPoints = mMaxTouchPoints;
|
||||
}
|
||||
|
@ -547,6 +549,8 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
|
||||
ScreenIntSize GetInnerSize();
|
||||
|
||||
nsRect GetVisibleRect();
|
||||
|
||||
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
|
||||
void DoFakeShow(const ShowInfo& aShowInfo);
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef mozilla_dom_EffectsInfo_h
|
||||
#define mozilla_dom_EffectsInfo_h
|
||||
|
||||
#include "nsRect.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -14,29 +16,37 @@ namespace dom {
|
|||
* An EffectsInfo contains information for a remote browser about the graphical
|
||||
* effects that are being applied to it by ancestor browsers in different
|
||||
* processes.
|
||||
*
|
||||
* TODO: This struct currently only reports visibility, and should be extended
|
||||
* with information on clipping and scaling.
|
||||
*/
|
||||
class EffectsInfo {
|
||||
public:
|
||||
EffectsInfo() { *this = EffectsInfo::FullyHidden(); }
|
||||
static EffectsInfo FullyVisible() { return EffectsInfo{true}; }
|
||||
static EffectsInfo FullyHidden() { return EffectsInfo{false}; }
|
||||
|
||||
static EffectsInfo VisibleWithinRect(const nsRect& aVisibleRect,
|
||||
float aScaleX, float aScaleY) {
|
||||
return EffectsInfo{aVisibleRect, aScaleX, aScaleY};
|
||||
}
|
||||
static EffectsInfo FullyHidden() { return EffectsInfo{nsRect(), 1.0f, 1.0f}; }
|
||||
|
||||
bool operator==(const EffectsInfo& aOther) {
|
||||
return mVisible == aOther.mVisible;
|
||||
return mVisibleRect == aOther.mVisibleRect && mScaleX == aOther.mScaleX &&
|
||||
mScaleY == aOther.mScaleY;
|
||||
}
|
||||
bool operator!=(const EffectsInfo& aOther) { return !(*this == aOther); }
|
||||
|
||||
// If you add new state here, you must also update operator==
|
||||
bool mVisible;
|
||||
/*
|
||||
* TODO: Add information for ancestor scaling and clipping.
|
||||
*/
|
||||
bool IsVisible() const { return !mVisibleRect.IsEmpty(); }
|
||||
|
||||
// The visible rect of this browser relative to the root frame. If this is
|
||||
// empty then the browser can be considered invisible.
|
||||
nsRect mVisibleRect;
|
||||
// The desired scale factors to apply to rasterized content to match
|
||||
// transforms applied in ancestor browsers.
|
||||
float mScaleX;
|
||||
float mScaleY;
|
||||
// If you add new fields here, you must also update operator==
|
||||
|
||||
private:
|
||||
explicit EffectsInfo(bool aVisible) : mVisible(aVisible) {}
|
||||
EffectsInfo(const nsRect& aVisibleRect, float aScaleX, float aScaleY)
|
||||
: mVisibleRect(aVisibleRect), mScaleX(aScaleX), mScaleY(aScaleY) {}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -81,12 +81,16 @@ struct ParamTraits<mozilla::dom::EffectsInfo> {
|
|||
typedef mozilla::dom::EffectsInfo paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam) {
|
||||
WriteParam(aMsg, aParam.mVisible);
|
||||
WriteParam(aMsg, aParam.mVisibleRect);
|
||||
WriteParam(aMsg, aParam.mScaleX);
|
||||
WriteParam(aMsg, aParam.mScaleY);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter,
|
||||
paramType* aResult) {
|
||||
return ReadParam(aMsg, aIter, &aResult->mVisible);
|
||||
return ReadParam(aMsg, aIter, &aResult->mVisibleRect) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScaleX) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScaleY);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1433,6 +1433,12 @@ class Connection final {
|
|||
|
||||
void AssertIsOnOwningThread() const { NS_ASSERT_OWNINGTHREAD(Connection); }
|
||||
|
||||
QuotaClient* GetQuotaClient() const {
|
||||
MOZ_ASSERT(mQuotaClient);
|
||||
|
||||
return mQuotaClient;
|
||||
}
|
||||
|
||||
ArchivedOriginScope* GetArchivedOriginScope() const {
|
||||
return mArchivedOriginScope;
|
||||
}
|
||||
|
@ -1479,6 +1485,12 @@ class Connection final {
|
|||
nsresult GetCachedStatement(const nsACString& aQuery,
|
||||
CachedStatement* aCachedStatement);
|
||||
|
||||
nsresult BeginWriteTransaction();
|
||||
|
||||
nsresult CommitWriteTransaction();
|
||||
|
||||
nsresult RollbackWriteTransaction();
|
||||
|
||||
private:
|
||||
// Only created by ConnectionThread.
|
||||
Connection(ConnectionThread* aConnectionThread, const nsACString& aSuffix,
|
||||
|
@ -2819,6 +2831,30 @@ class QuotaClient::MatchFunction final : public mozIStorageFunction {
|
|||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Helper classes
|
||||
******************************************************************************/
|
||||
|
||||
class MOZ_STACK_CLASS AutoWriteTransaction final {
|
||||
Connection* mConnection;
|
||||
Maybe<MutexAutoLock> mShadowDatabaseLock;
|
||||
bool mShadowWrites;
|
||||
|
||||
public:
|
||||
explicit AutoWriteTransaction(bool aShadowWrites);
|
||||
|
||||
~AutoWriteTransaction();
|
||||
|
||||
nsresult Start(Connection* aConnection);
|
||||
|
||||
nsresult Commit();
|
||||
|
||||
private:
|
||||
nsresult LockAndAttachShadowDatabase(Connection* aConnection);
|
||||
|
||||
nsresult DetachShadowDatabaseAndUnlock();
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Globals
|
||||
******************************************************************************/
|
||||
|
@ -4342,6 +4378,60 @@ nsresult Connection::GetCachedStatement(const nsACString& aQuery,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult Connection::BeginWriteTransaction() {
|
||||
AssertIsOnConnectionThread();
|
||||
MOZ_ASSERT(mStorageConnection);
|
||||
|
||||
CachedStatement stmt;
|
||||
nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING("BEGIN IMMEDIATE;"),
|
||||
&stmt);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->Execute();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult Connection::CommitWriteTransaction() {
|
||||
AssertIsOnConnectionThread();
|
||||
MOZ_ASSERT(mStorageConnection);
|
||||
|
||||
CachedStatement stmt;
|
||||
nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING("COMMIT;"), &stmt);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->Execute();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult Connection::RollbackWriteTransaction() {
|
||||
AssertIsOnConnectionThread();
|
||||
MOZ_ASSERT(mStorageConnection);
|
||||
|
||||
CachedStatement stmt;
|
||||
nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING("ROLLBACK;"), &stmt);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// This may fail if SQLite already rolled back the transaction so ignore any
|
||||
// errors.
|
||||
Unused << stmt->Execute();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Connection::ScheduleFlush() {
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mWriteOptimizer.HasWrites());
|
||||
|
@ -4497,69 +4587,9 @@ nsresult Connection::FlushOp::DoDatastoreWork() {
|
|||
AssertIsOnConnectionThread();
|
||||
MOZ_ASSERT(mConnection);
|
||||
|
||||
class MOZ_STACK_CLASS AutoDetach final {
|
||||
nsCOMPtr<mozIStorageConnection> mConnection;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
AutoWriteTransaction autoWriteTransaction(mShadowWrites);
|
||||
|
||||
public:
|
||||
explicit AutoDetach(
|
||||
mozIStorageConnection* aConnection MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: mConnection(aConnection) {
|
||||
MOZ_ASSERT(aConnection);
|
||||
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
~AutoDetach() {
|
||||
if (mConnection) {
|
||||
nsresult rv = DetachShadowDatabase(mConnection);
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
}
|
||||
|
||||
void release() { mConnection = nullptr; }
|
||||
|
||||
private:
|
||||
explicit AutoDetach(const AutoDetach&) = delete;
|
||||
AutoDetach& operator=(const AutoDetach&) = delete;
|
||||
AutoDetach& operator=(AutoDetach&&) = delete;
|
||||
};
|
||||
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
MOZ_ASSERT(quotaManager);
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> storageConnection =
|
||||
mConnection->StorageConnection();
|
||||
MOZ_ASSERT(storageConnection);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
Maybe<MutexAutoLock> shadowDatabaseLock;
|
||||
|
||||
Maybe<AutoDetach> autoDetach;
|
||||
|
||||
if (mShadowWrites) {
|
||||
MOZ_ASSERT(mConnection->mQuotaClient);
|
||||
|
||||
shadowDatabaseLock.emplace(
|
||||
mConnection->mQuotaClient->ShadowDatabaseMutex());
|
||||
|
||||
rv = AttachShadowDatabase(quotaManager->GetBasePath(), storageConnection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
autoDetach.emplace(storageConnection);
|
||||
}
|
||||
|
||||
CachedStatement stmt;
|
||||
rv = mConnection->GetCachedStatement(NS_LITERAL_CSTRING("BEGIN IMMEDIATE;"),
|
||||
&stmt);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->Execute();
|
||||
nsresult rv = autoWriteTransaction.Start(mConnection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -4588,34 +4618,19 @@ nsresult Connection::FlushOp::DoDatastoreWork() {
|
|||
return rv;
|
||||
}
|
||||
|
||||
rv = mConnection->GetCachedStatement(NS_LITERAL_CSTRING("COMMIT;"), &stmt);
|
||||
rv = autoWriteTransaction.Commit();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->Execute();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (mShadowWrites) {
|
||||
autoDetach->release();
|
||||
|
||||
rv = DetachShadowDatabase(storageConnection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
autoDetach.reset();
|
||||
|
||||
shadowDatabaseLock.reset();
|
||||
}
|
||||
|
||||
rv = usageJournalFile->Remove(false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
MOZ_ASSERT(quotaManager);
|
||||
|
||||
RefPtr<Runnable> runnable =
|
||||
NS_NewRunnableFunction("dom::localstorage::UpdateUsageRunnable",
|
||||
[origin = mConnection->Origin(), usage]() {
|
||||
|
@ -9351,5 +9366,124 @@ QuotaClient::MatchFunction::OnFunctionCall(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* AutoWriteTransaction
|
||||
******************************************************************************/
|
||||
|
||||
AutoWriteTransaction::AutoWriteTransaction(bool aShadowWrites)
|
||||
: mConnection(nullptr)
|
||||
, mShadowWrites(aShadowWrites)
|
||||
{
|
||||
AssertIsOnConnectionThread();
|
||||
|
||||
MOZ_COUNT_CTOR(mozilla::dom::AutoWriteTransaction);
|
||||
}
|
||||
|
||||
AutoWriteTransaction::~AutoWriteTransaction() {
|
||||
AssertIsOnConnectionThread();
|
||||
|
||||
MOZ_COUNT_DTOR(mozilla::dom::AutoWriteTransaction);
|
||||
|
||||
if (mConnection) {
|
||||
if (NS_FAILED(mConnection->RollbackWriteTransaction())) {
|
||||
NS_WARNING("Failed to rollback write transaction!");
|
||||
}
|
||||
|
||||
if (mShadowWrites && NS_FAILED(DetachShadowDatabaseAndUnlock())) {
|
||||
NS_WARNING("Failed to detach shadow database!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult AutoWriteTransaction::Start(Connection* aConnection) {
|
||||
AssertIsOnConnectionThread();
|
||||
MOZ_ASSERT(aConnection);
|
||||
MOZ_ASSERT(!mConnection);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (mShadowWrites) {
|
||||
rv = LockAndAttachShadowDatabase(aConnection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
rv = aConnection->BeginWriteTransaction();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mConnection = aConnection;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult AutoWriteTransaction::Commit() {
|
||||
AssertIsOnConnectionThread();
|
||||
MOZ_ASSERT(mConnection);
|
||||
|
||||
nsresult rv = mConnection->CommitWriteTransaction();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (mShadowWrites) {
|
||||
rv = DetachShadowDatabaseAndUnlock();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
mConnection = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult AutoWriteTransaction::LockAndAttachShadowDatabase(Connection* aConnection) {
|
||||
AssertIsOnConnectionThread();
|
||||
MOZ_ASSERT(aConnection);
|
||||
MOZ_ASSERT(!mConnection);
|
||||
MOZ_ASSERT(mShadowDatabaseLock.isNothing());
|
||||
MOZ_ASSERT(mShadowWrites);
|
||||
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
MOZ_ASSERT(quotaManager);
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> storageConnection =
|
||||
aConnection->StorageConnection();
|
||||
MOZ_ASSERT(storageConnection);
|
||||
|
||||
mShadowDatabaseLock.emplace(
|
||||
aConnection->GetQuotaClient()->ShadowDatabaseMutex());
|
||||
|
||||
nsresult rv = AttachShadowDatabase(quotaManager->GetBasePath(), storageConnection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult AutoWriteTransaction::DetachShadowDatabaseAndUnlock() {
|
||||
AssertIsOnConnectionThread();
|
||||
MOZ_ASSERT(mConnection);
|
||||
MOZ_ASSERT(mShadowDatabaseLock.isSome());
|
||||
MOZ_ASSERT(mShadowWrites);
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> storageConnection =
|
||||
mConnection->StorageConnection();
|
||||
MOZ_ASSERT(storageConnection);
|
||||
|
||||
nsresult rv = DetachShadowDatabase(storageConnection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mShadowDatabaseLock.reset();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -85,6 +85,18 @@ function resetOriginLimit() {
|
|||
Services.prefs.clearUserPref("dom.storage.default_quota");
|
||||
}
|
||||
|
||||
function setTimeout(callback, timeout) {
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
|
||||
timer.initWithCallback({
|
||||
notify() {
|
||||
callback();
|
||||
},
|
||||
}, timeout, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
function init() {
|
||||
let request = Services.qms.init();
|
||||
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
|
||||
/**
|
||||
* This test is mainly to verify that the flush operation detaches the shadow
|
||||
* database in the event of early return due to error. See bug 1559029.
|
||||
*/
|
||||
|
||||
async function testSteps() {
|
||||
const principal1 = getPrincipal("http://example1.com");
|
||||
|
||||
const usageFile1 =
|
||||
getRelativeFile("storage/default/http+++example1.com/ls/usage");
|
||||
|
||||
const principal2 = getPrincipal("http://example2.com");
|
||||
|
||||
const data = {
|
||||
key: "foo",
|
||||
value: "bar",
|
||||
};
|
||||
|
||||
const flushSleepTimeSec = 6;
|
||||
|
||||
info("Setting prefs");
|
||||
|
||||
Services.prefs.setBoolPref("dom.storage.next_gen", true);
|
||||
|
||||
info("Getting storage 1");
|
||||
|
||||
let storage1 = getLocalStorage(principal1);
|
||||
|
||||
info("Adding item");
|
||||
|
||||
storage1.setItem(data.key, data.value);
|
||||
|
||||
info("Creating usage as a directory");
|
||||
|
||||
// This will cause a failure during the flush for first principal.
|
||||
usageFile1.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
|
||||
|
||||
info("Getting storage 2");
|
||||
|
||||
let storage2 = getLocalStorage(principal2);
|
||||
|
||||
info("Adding item");
|
||||
|
||||
storage2.setItem(data.key, data.value);
|
||||
|
||||
// The flush for second principal shouldn't be affected by failed flush for
|
||||
// first principal.
|
||||
|
||||
info("Sleeping for " + flushSleepTimeSec + " seconds to let all flushes " +
|
||||
"finish");
|
||||
|
||||
await new Promise(function(resolve) {
|
||||
setTimeout(resolve, flushSleepTimeSec * 1000);
|
||||
});
|
||||
|
||||
info("Resetting");
|
||||
|
||||
// Wait for all database connections to close.
|
||||
let request = reset();
|
||||
await requestFinished(request);
|
||||
}
|
|
@ -33,6 +33,7 @@ run-sequentially = test_databaseShadowing_clearOriginsByPrefix2.js depends on a
|
|||
[test_databaseShadowing_clearOriginsByPrefix2.js]
|
||||
run-sequentially = this test depends on a file produced by test_databaseShadowing_clearOriginsByPrefix1.js
|
||||
[test_eviction.js]
|
||||
[test_flushing.js]
|
||||
[test_groupLimit.js]
|
||||
[test_groupMismatch.js]
|
||||
[test_largeItems.js]
|
||||
|
|
|
@ -406,7 +406,7 @@ void APZCCallbackHelper::InitializeRootDisplayport(PresShell* aPresShell) {
|
|||
&viewId)) {
|
||||
nsPresContext* pc = aPresShell->GetPresContext();
|
||||
// This code is only correct for root content or toplevel documents.
|
||||
MOZ_ASSERT(!pc || pc->IsRootContentDocument() ||
|
||||
MOZ_ASSERT(!pc || pc->IsRootContentDocumentCrossProcess() ||
|
||||
!pc->GetParentPresContext());
|
||||
nsIFrame* frame = aPresShell->GetRootScrollFrame();
|
||||
if (!frame) {
|
||||
|
|
|
@ -1992,7 +1992,7 @@ MOZ_MUST_USE bool TokenStreamSpecific<Unit, AnyCharsAccess>::getDirective(
|
|||
}
|
||||
|
||||
if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
|
||||
if (unicode::IsSpaceOrBOM2(unit)) {
|
||||
if (unicode::IsSpace(AssertedCast<Latin1Char>(unit))) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2016,13 +2016,13 @@ MOZ_MUST_USE bool TokenStreamSpecific<Unit, AnyCharsAccess>::getDirective(
|
|||
// This ignores encoding errors: subsequent caller-side code to
|
||||
// handle the remaining source text in the comment will do so.
|
||||
PeekedCodePoint<Unit> peeked = this->sourceUnits.peekCodePoint();
|
||||
if (peeked.isNone() || unicode::IsSpaceOrBOM2(peeked.codePoint())) {
|
||||
if (peeked.isNone() || unicode::IsSpace(peeked.codePoint())) {
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!IsLineTerminator(peeked.codePoint()),
|
||||
"!IsSpaceOrBOM2 must imply !IsLineTerminator or else we'll "
|
||||
"fail to maintain line-info/flags for EOL");
|
||||
"!IsSpace must imply !IsLineTerminator or else we'll fail to "
|
||||
"maintain line-info/flags for EOL");
|
||||
this->sourceUnits.consumeKnownCodePoint(peeked);
|
||||
|
||||
if (!appendCodePointToCharBuffer(peeked.codePoint())) {
|
||||
|
@ -2743,12 +2743,11 @@ MOZ_MUST_USE bool TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(
|
|||
}
|
||||
|
||||
if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
|
||||
// Non-ASCII code points can only be identifiers or whitespace.
|
||||
// It would be nice to compute these *after* discarding whitespace,
|
||||
// but IN A WORLD where |unicode::IsSpaceOrBOM2| requires consuming
|
||||
// a variable number of code points, it's easier to assume it's an
|
||||
// identifier and maybe do a little wasted work, than to unget and
|
||||
// compute and reget if whitespace.
|
||||
// Non-ASCII code points can only be identifiers or whitespace. It would
|
||||
// be nice to compute these *after* discarding whitespace, but IN A WORLD
|
||||
// where |unicode::IsSpace| requires consuming a variable number of code
|
||||
// units, it's easier to assume it's an identifier and maybe do a little
|
||||
// wasted work, than to unget and compute and reget if whitespace.
|
||||
TokenStart start(this->sourceUnits, 0);
|
||||
const Unit* identStart = this->sourceUnits.addressOfNextCodeUnit();
|
||||
|
||||
|
@ -2760,7 +2759,7 @@ MOZ_MUST_USE bool TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(
|
|||
}
|
||||
|
||||
char32_t cp = peeked.codePoint();
|
||||
if (unicode::IsSpaceOrBOM2(cp)) {
|
||||
if (unicode::IsSpace(cp)) {
|
||||
this->sourceUnits.consumeKnownCodePoint(peeked);
|
||||
if (IsLineTerminator(cp)) {
|
||||
if (!updateLineInfoForEOL()) {
|
||||
|
|
|
@ -19,8 +19,7 @@ function test()
|
|||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
var bomchars = ['\uFFFE',
|
||||
'\uFEFF'];
|
||||
var bomchars = ['\uFEFF'];
|
||||
|
||||
for (var i = 0; i < bomchars.length; i++)
|
||||
{
|
||||
|
|
|
@ -80,7 +80,6 @@ constexpr char16_t GREEK_SMALL_LETTER_SIGMA = 0x03C3;
|
|||
constexpr char16_t LINE_SEPARATOR = 0x2028;
|
||||
constexpr char16_t PARA_SEPARATOR = 0x2029;
|
||||
constexpr char16_t REPLACEMENT_CHARACTER = 0xFFFD;
|
||||
constexpr char16_t BYTE_ORDER_MARK2 = 0xFFFE;
|
||||
|
||||
const char16_t LeadSurrogateMin = 0xD800;
|
||||
const char16_t LeadSurrogateMax = 0xDBFF;
|
||||
|
@ -204,19 +203,28 @@ inline bool IsUnicodeIDStart(uint32_t codePoint) {
|
|||
return IsUnicodeIDStart(char16_t(codePoint));
|
||||
}
|
||||
|
||||
// IsSpace checks if a code point is included in the merged set of WhiteSpace
|
||||
// and LineTerminator specified by #sec-white-space and #sec-line-terminators.
|
||||
// We combine them because nearly every calling function wants this, excepting
|
||||
// only some tokenizer code that necessarily handles LineTerminator specially
|
||||
// due to UTF-8/UTF-16 template specialization.
|
||||
inline bool IsSpace(char16_t ch) {
|
||||
/*
|
||||
* IsSpace checks if some character is included in the merged set
|
||||
* of WhiteSpace and LineTerminator, specified by ES2016 11.2 and 11.3.
|
||||
* We combined them, because in practice nearly every
|
||||
* calling function wants this, except some code in the tokenizer.
|
||||
*
|
||||
* We use a lookup table for ASCII-7 characters, because they are
|
||||
* very common and must be handled quickly in the tokenizer.
|
||||
* NO-BREAK SPACE is supposed to be the most common character not in
|
||||
* this range, so we inline this case, too.
|
||||
*/
|
||||
// ASCII code points are very common and must be handled quickly, so use a
|
||||
// lookup table for them.
|
||||
if (ch < 128) {
|
||||
return js_isspace[ch];
|
||||
}
|
||||
|
||||
// NO-BREAK SPACE is supposed to be the most common non-ASCII WhiteSpace code
|
||||
// point, so inline its handling too.
|
||||
if (ch == NO_BREAK_SPACE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return CharInfo(ch).isSpace();
|
||||
}
|
||||
|
||||
inline bool IsSpace(JS::Latin1Char ch) {
|
||||
if (ch < 128) {
|
||||
return js_isspace[ch];
|
||||
}
|
||||
|
@ -225,16 +233,20 @@ inline bool IsSpace(char16_t ch) {
|
|||
return true;
|
||||
}
|
||||
|
||||
return CharInfo(ch).isSpace();
|
||||
MOZ_ASSERT(!CharInfo(ch).isSpace());
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool IsSpaceOrBOM2(char32_t ch) {
|
||||
inline bool IsSpace(char ch) {
|
||||
return IsSpace(static_cast<JS::Latin1Char>(ch));
|
||||
}
|
||||
|
||||
inline bool IsSpace(char32_t ch) {
|
||||
if (ch < 128) {
|
||||
return js_isspace[ch];
|
||||
}
|
||||
|
||||
/* We accept BOM2 (0xFFFE) for compatibility reasons in the parser. */
|
||||
if (ch == NO_BREAK_SPACE || ch == BYTE_ORDER_MARK2) {
|
||||
if (ch == NO_BREAK_SPACE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "mozilla/StaticPrefs.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsCharTraits.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/DocumentInlines.h"
|
||||
#include "nsFontMetrics.h"
|
||||
|
@ -3786,12 +3787,20 @@ nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
|
|||
builder->SetInActiveDocShell(isActive);
|
||||
}
|
||||
|
||||
nsRect rootVisualOverflow = aFrame->GetVisualOverflowRectRelativeToSelf();
|
||||
|
||||
// If we are in a remote browser, then apply clipping from ancestor browsers
|
||||
if (BrowserChild* browserChild = BrowserChild::GetFrom(presShell)) {
|
||||
rootVisualOverflow.IntersectRect(rootVisualOverflow,
|
||||
browserChild->GetVisibleRect());
|
||||
}
|
||||
|
||||
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
|
||||
if (rootScrollFrame && !aFrame->GetParent()) {
|
||||
nsIScrollableFrame* rootScrollableFrame =
|
||||
presShell->GetRootScrollFrameAsScrollable();
|
||||
MOZ_ASSERT(rootScrollableFrame);
|
||||
nsRect displayPortBase = aFrame->GetVisualOverflowRectRelativeToSelf();
|
||||
nsRect displayPortBase = rootVisualOverflow;
|
||||
nsRect temp = displayPortBase;
|
||||
Unused << rootScrollableFrame->DecideScrollableLayer(
|
||||
builder, &displayPortBase, &temp,
|
||||
|
@ -3806,7 +3815,7 @@ nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
|
|||
// |ignoreViewportScrolling| and |usingDisplayPort| are persistent
|
||||
// document-rendering state. We rely on PresShell to flush
|
||||
// retained layers as needed when that persistent state changes.
|
||||
visibleRegion = aFrame->GetVisualOverflowRectRelativeToSelf();
|
||||
visibleRegion = rootVisualOverflow;
|
||||
} else {
|
||||
visibleRegion = aDirtyRegion;
|
||||
}
|
||||
|
@ -8465,10 +8474,9 @@ static bool UpdateCompositionBoundsForRCDRSF(ParentLayerRect& aCompBounds,
|
|||
#endif
|
||||
|
||||
if (widget) {
|
||||
LayoutDeviceIntRect widgetBounds = widget->GetBounds();
|
||||
widgetBounds.MoveTo(0, 0);
|
||||
aCompBounds = ParentLayerRect(ViewAs<ParentLayerPixel>(
|
||||
widgetBounds,
|
||||
LayoutDeviceIntRect(LayoutDeviceIntPoint(),
|
||||
widget->GetCompositionSize()),
|
||||
PixelCastJustification::LayoutDeviceIsParentLayerForRCDRSF));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3801,8 +3801,12 @@ bool ScrollFrameHelper::DecideScrollableLayer(
|
|||
if (aSetBase) {
|
||||
nsRect displayportBase = *aVisibleRect;
|
||||
nsPresContext* pc = mOuter->PresContext();
|
||||
if (mIsRoot &&
|
||||
(pc->IsRootContentDocument() || !pc->GetParentPresContext())) {
|
||||
|
||||
bool isContentRootDoc = pc->IsRootContentDocumentCrossProcess();
|
||||
bool isChromeRootDoc =
|
||||
!pc->Document()->IsContentDocument() && !pc->GetParentPresContext();
|
||||
|
||||
if (mIsRoot && (isContentRootDoc || isChromeRootDoc)) {
|
||||
displayportBase =
|
||||
nsRect(nsPoint(0, 0),
|
||||
nsLayoutUtils::CalculateCompositionSizeForFrame(mOuter));
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/StaticPrefs.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/HTMLFrameElement.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
|
@ -1404,8 +1405,20 @@ already_AddRefed<mozilla::layers::Layer> nsDisplayRemote::BuildLayer(
|
|||
|
||||
if (RefPtr<RemoteBrowser> remoteBrowser =
|
||||
GetFrameLoader()->GetRemoteBrowser()) {
|
||||
// Adjust mItemVisibleRect, which is relative to the reference frame, to be
|
||||
// relative to this frame
|
||||
nsRect visibleRect;
|
||||
if (aContainerParameters.mItemVisibleRect) {
|
||||
visibleRect = *aContainerParameters.mItemVisibleRect - ToReferenceFrame();
|
||||
} else {
|
||||
visibleRect = mFrame->GetContentRectRelativeToSelf();
|
||||
}
|
||||
|
||||
// Generate an effects update notifying the browser it is visible
|
||||
aBuilder->AddEffectUpdate(remoteBrowser, EffectsInfo::FullyVisible());
|
||||
aBuilder->AddEffectUpdate(remoteBrowser,
|
||||
EffectsInfo::VisibleWithinRect(
|
||||
visibleRect, aContainerParameters.mXScale,
|
||||
aContainerParameters.mYScale));
|
||||
// FrameLayerBuilder will take care of notifying the browser when it is no
|
||||
// longer visible
|
||||
}
|
||||
|
@ -1465,8 +1478,10 @@ bool nsDisplayRemote::CreateWebRenderCommands(
|
|||
if (RefPtr<RemoteBrowser> remoteBrowser =
|
||||
GetFrameLoader()->GetRemoteBrowser()) {
|
||||
// Generate an effects update notifying the browser it is visible
|
||||
aDisplayListBuilder->AddEffectUpdate(remoteBrowser,
|
||||
EffectsInfo::FullyVisible());
|
||||
// TODO - Gather visibleRect and scaling factors
|
||||
aDisplayListBuilder->AddEffectUpdate(
|
||||
remoteBrowser, EffectsInfo::VisibleWithinRect(
|
||||
mFrame->GetContentRectRelativeToSelf(), 1.0f, 1.0f));
|
||||
|
||||
// Create a WebRenderRemoteData to notify the RemoteBrowser when it is no
|
||||
// longer visible
|
||||
|
|
|
@ -4657,6 +4657,7 @@ void ContainerState::ProcessDisplayItems(nsDisplayList* aList) {
|
|||
transformNode = transformNode->Parent();
|
||||
}
|
||||
|
||||
nsRect itemVisibleRectAu = itemContent;
|
||||
if (transformNode) {
|
||||
// If we are within transform, transform itemContent and itemDrawRect.
|
||||
MOZ_ASSERT(transformNode);
|
||||
|
@ -4818,6 +4819,15 @@ void ContainerState::ProcessDisplayItems(nsDisplayList* aList) {
|
|||
ContainerLayerParameters params = mParameters;
|
||||
params.mBackgroundColor = uniformColor;
|
||||
params.mLayerCreationHint = GetLayerCreationHint(itemAGR);
|
||||
if (!transformNode) {
|
||||
params.mItemVisibleRect = &itemVisibleRectAu;
|
||||
} else {
|
||||
// We only use mItemVisibleRect for getting the visible rect for
|
||||
// remote browsers (which should never have inactive transforms), so we
|
||||
// avoid doing transforms on itemVisibleRectAu above and can't report
|
||||
// an accurate bounds here.
|
||||
params.mItemVisibleRect = nullptr;
|
||||
}
|
||||
params.mScrollMetadataASR =
|
||||
ActiveScrolledRoot::IsAncestor(scrollMetadataASR,
|
||||
mContainerScrollMetadataASR)
|
||||
|
|
|
@ -285,6 +285,7 @@ struct ContainerLayerParameters {
|
|||
: mXScale(aXScale),
|
||||
mYScale(aYScale),
|
||||
mLayerContentsVisibleRect(nullptr),
|
||||
mItemVisibleRect(nullptr),
|
||||
mBackgroundColor(NS_RGBA(0, 0, 0, 0)),
|
||||
mScrollMetadataASR(nullptr),
|
||||
mCompositorASR(nullptr),
|
||||
|
@ -298,6 +299,7 @@ struct ContainerLayerParameters {
|
|||
: mXScale(aXScale),
|
||||
mYScale(aYScale),
|
||||
mLayerContentsVisibleRect(nullptr),
|
||||
mItemVisibleRect(nullptr),
|
||||
mOffset(aOffset),
|
||||
mBackgroundColor(aParent.mBackgroundColor),
|
||||
mScrollMetadataASR(aParent.mScrollMetadataASR),
|
||||
|
@ -320,6 +322,11 @@ struct ContainerLayerParameters {
|
|||
*/
|
||||
nsIntRect* mLayerContentsVisibleRect;
|
||||
|
||||
/**
|
||||
* If non-null, the rectangle which stores the item's visible rect.
|
||||
*/
|
||||
nsRect* mItemVisibleRect;
|
||||
|
||||
/**
|
||||
* An offset to apply to all child layers created.
|
||||
*/
|
||||
|
|
|
@ -101,7 +101,8 @@ enum class PartialUpdateFailReason {
|
|||
RebuildLimit,
|
||||
FrameType,
|
||||
Disabled,
|
||||
Content
|
||||
Content,
|
||||
VisibleRect,
|
||||
};
|
||||
|
||||
struct RetainedDisplayListMetrics {
|
||||
|
@ -146,6 +147,8 @@ struct RetainedDisplayListMetrics {
|
|||
return "Disabled";
|
||||
case PartialUpdateFailReason::Content:
|
||||
return "Content";
|
||||
case PartialUpdateFailReason::VisibleRect:
|
||||
return "VisibleRect";
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Enum value not handled!");
|
||||
}
|
||||
|
@ -254,6 +257,7 @@ struct RetainedDisplayListBuilder {
|
|||
|
||||
nsDisplayListBuilder mBuilder;
|
||||
RetainedDisplayList mList;
|
||||
nsRect mPreviousVisibleRect;
|
||||
WeakFrame mPreviousCaret;
|
||||
RetainedDisplayListMetrics mMetrics;
|
||||
};
|
||||
|
|
|
@ -2882,11 +2882,19 @@ FrameLayerBuilder* nsDisplayList::BuildLayers(nsDisplayListBuilder* aBuilder,
|
|||
rootLayer->SetScrollMetadata(nsTArray<ScrollMetadata>());
|
||||
}
|
||||
|
||||
float rootLayerResolution = StaticPrefs::LayoutUseContainersForRootFrames()
|
||||
? presShell->GetResolution()
|
||||
: 1.0f;
|
||||
ContainerLayerParameters containerParameters(rootLayerResolution,
|
||||
rootLayerResolution);
|
||||
float resolutionUniform = StaticPrefs::LayoutUseContainersForRootFrames()
|
||||
? presShell->GetResolution()
|
||||
: 1.0f;
|
||||
float resolutionX = resolutionUniform;
|
||||
float resolutionY = resolutionUniform;
|
||||
|
||||
// If we are in a remote browser, then apply scaling from ancestor browsers
|
||||
if (BrowserChild* browserChild = BrowserChild::GetFrom(presShell)) {
|
||||
resolutionX *= browserChild->GetEffectsInfo().mScaleX;
|
||||
resolutionY *= browserChild->GetEffectsInfo().mScaleY;
|
||||
}
|
||||
|
||||
ContainerLayerParameters containerParameters(resolutionX, resolutionY);
|
||||
|
||||
{
|
||||
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
|
||||
|
@ -2906,11 +2914,10 @@ FrameLayerBuilder* nsDisplayList::BuildLayers(nsDisplayListBuilder* aBuilder,
|
|||
if (!root) {
|
||||
return nullptr;
|
||||
}
|
||||
// Root is being scaled up by the X/Y resolution. Scale it back down.
|
||||
root->SetPostScale(1.0f / resolutionX, 1.0f / resolutionY);
|
||||
if (StaticPrefs::LayoutUseContainersForRootFrames()) {
|
||||
// Root is being scaled up by the X/Y resolution. Scale it back down.
|
||||
root->SetPostScale(1.0f / containerParameters.mXScale,
|
||||
1.0f / containerParameters.mYScale);
|
||||
root->SetScaleToResolution(containerParameters.mXScale);
|
||||
root->SetScaleToResolution(resolutionUniform);
|
||||
}
|
||||
|
||||
auto callback = [root](ScrollableLayerGuid::ViewID aScrollId) -> bool {
|
||||
|
|
|
@ -1158,6 +1158,15 @@ LayoutDeviceIntRect PuppetWidget::GetScreenBounds() {
|
|||
return LayoutDeviceIntRect(WidgetToScreenOffset(), mBounds.Size());
|
||||
}
|
||||
|
||||
LayoutDeviceIntSize PuppetWidget::GetCompositionSize() {
|
||||
if (!mBrowserChild) {
|
||||
return nsBaseWidget::GetCompositionSize();
|
||||
}
|
||||
CSSSize visibleSize =
|
||||
CSSPixel::FromAppUnits(mBrowserChild->GetVisibleRect().Size());
|
||||
return RoundedToInt(visibleSize * GetDefaultScale());
|
||||
}
|
||||
|
||||
uint32_t PuppetWidget::GetMaxTouchPoints() const {
|
||||
uint32_t maxTouchPoints = 0;
|
||||
if (mBrowserChild) {
|
||||
|
|
|
@ -242,6 +242,8 @@ class PuppetWidget : public nsBaseWidget,
|
|||
|
||||
virtual LayoutDeviceIntRect GetScreenBounds() override;
|
||||
|
||||
virtual LayoutDeviceIntSize GetCompositionSize() override;
|
||||
|
||||
virtual MOZ_MUST_USE nsresult StartPluginIME(
|
||||
const mozilla::WidgetKeyboardEvent& aKeyboardEvent, int32_t aPanelX,
|
||||
int32_t aPanelY, nsString& aCommitted) override;
|
||||
|
|
|
@ -937,6 +937,16 @@ class nsIWidget : public nsISupports {
|
|||
return GetClientBounds().Size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the bounds of this widget that will be visible when
|
||||
* rendered.
|
||||
*
|
||||
* @return the width and height of the composition size of this widget.
|
||||
*/
|
||||
virtual LayoutDeviceIntSize GetCompositionSize() {
|
||||
return GetBounds().Size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the background color for this widget
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче