зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound. CLOSED TREE
This commit is contained in:
Коммит
aca35453cf
|
@ -206,10 +206,10 @@ AccessibleWrap::GetSelectionBounds(int32_t* aStartOffset, int32_t* aEndOffset) {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
uint32_t
|
||||
AccessibleWrap::GetFlags(role aRole, uint64_t aState)
|
||||
{
|
||||
uint64_t flags = 0;
|
||||
uint32_t flags = 0;
|
||||
if (aState & states::CHECKABLE) {
|
||||
flags |= java::SessionAccessibility::FLAG_CHECKABLE;
|
||||
}
|
||||
|
@ -388,7 +388,7 @@ AccessibleWrap::ToBundle()
|
|||
|
||||
role role = WrapperRole();
|
||||
uint64_t state = State();
|
||||
uint64_t flags = GetFlags(role, state);
|
||||
uint32_t flags = GetFlags(role, state);
|
||||
GECKOBUNDLE_PUT(nodeInfo, "flags", java::sdk::Integer::ValueOf(flags));
|
||||
GECKOBUNDLE_PUT(nodeInfo, "className", java::sdk::Integer::ValueOf(AndroidClass()));
|
||||
|
||||
|
@ -539,3 +539,44 @@ AccessibleWrap::ToBundle()
|
|||
|
||||
return nodeInfo;
|
||||
}
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef
|
||||
AccessibleWrap::ToSmallBundle()
|
||||
{
|
||||
return ToSmallBundle(State(), Bounds());
|
||||
}
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef
|
||||
AccessibleWrap::ToSmallBundle(const uint64_t aState, const nsIntRect& aBounds)
|
||||
{
|
||||
GECKOBUNDLE_START(nodeInfo);
|
||||
GECKOBUNDLE_PUT(nodeInfo, "id", java::sdk::Integer::ValueOf(VirtualViewID()));
|
||||
|
||||
AccessibleWrap* parent = WrapperParent();
|
||||
GECKOBUNDLE_PUT(nodeInfo, "parentId",
|
||||
java::sdk::Integer::ValueOf(parent ? parent->VirtualViewID() : 0));
|
||||
|
||||
uint32_t flags = GetFlags(WrapperRole(), aState);
|
||||
GECKOBUNDLE_PUT(nodeInfo, "flags", java::sdk::Integer::ValueOf(flags));
|
||||
GECKOBUNDLE_PUT(nodeInfo, "className", java::sdk::Integer::ValueOf(AndroidClass()));
|
||||
|
||||
const int32_t data[4] = {
|
||||
aBounds.x, aBounds.y, aBounds.x + aBounds.width, aBounds.y + aBounds.height
|
||||
};
|
||||
GECKOBUNDLE_PUT(nodeInfo, "bounds", jni::IntArray::New(data, 4));
|
||||
|
||||
auto childCount = ChildCount();
|
||||
nsTArray<int32_t> children(childCount);
|
||||
for (uint32_t i = 0; i < childCount; ++i) {
|
||||
auto child = static_cast<AccessibleWrap*>(GetChildAt(i));
|
||||
children.AppendElement(child->VirtualViewID());
|
||||
}
|
||||
|
||||
GECKOBUNDLE_PUT(nodeInfo,
|
||||
"children",
|
||||
jni::IntArray::New(children.Elements(), children.Length()));
|
||||
|
||||
GECKOBUNDLE_FINISH(nodeInfo);
|
||||
|
||||
return nodeInfo;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,10 @@ public:
|
|||
|
||||
mozilla::java::GeckoBundle::LocalRef ToBundle();
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef ToSmallBundle(const uint64_t aState, const nsIntRect& aBounds);
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef ToSmallBundle();
|
||||
|
||||
int32_t AndroidClass()
|
||||
{
|
||||
return mID == kNoID ? java::SessionAccessibility::CLASSNAME_WEBVIEW
|
||||
|
@ -65,8 +69,7 @@ private:
|
|||
static void GetRoleDescription(role aRole,
|
||||
nsAString& aGeckoRole,
|
||||
nsAString& aRoleDescription);
|
||||
|
||||
static uint64_t GetFlags(role aRole, uint64_t aState);
|
||||
static uint32_t GetFlags(role aRole, uint64_t aState);
|
||||
};
|
||||
|
||||
static inline AccessibleWrap*
|
||||
|
|
|
@ -6,9 +6,15 @@
|
|||
|
||||
#include "DocAccessibleWrap.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "DocAccessibleChild.h"
|
||||
#include "nsAccessibilityService.h"
|
||||
#include "SessionAccessibility.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
const uint32_t kCacheRefreshInterval = 500;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DocAccessibleWrap
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -51,3 +57,117 @@ DocAccessibleWrap::GetAccessibleByID(int32_t aID) const
|
|||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessibleWrap::DoInitialUpdate()
|
||||
{
|
||||
DocAccessible::DoInitialUpdate();
|
||||
CacheViewport();
|
||||
}
|
||||
|
||||
nsresult
|
||||
DocAccessibleWrap::HandleAccEvent(AccEvent* aEvent)
|
||||
{
|
||||
switch(aEvent->GetEventType()) {
|
||||
case nsIAccessibleEvent::EVENT_SHOW:
|
||||
case nsIAccessibleEvent::EVENT_HIDE:
|
||||
case nsIAccessibleEvent::EVENT_SCROLLING_END:
|
||||
CacheViewport();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return DocAccessible::HandleAccEvent(aEvent);
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessibleWrap::CacheViewportCallback(nsITimer* aTimer, void* aDocAccParam)
|
||||
{
|
||||
RefPtr<DocAccessibleWrap> docAcc(dont_AddRef(
|
||||
reinterpret_cast<DocAccessibleWrap*>(aDocAccParam)));
|
||||
if (!docAcc) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIPresShell *presShell = docAcc->PresShell();
|
||||
if (!presShell) {
|
||||
return;
|
||||
}
|
||||
nsIFrame* rootFrame = presShell->GetRootFrame();
|
||||
if (!rootFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<nsIFrame*> frames;
|
||||
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
|
||||
nsRect scrollPort = sf ? sf->GetScrollPortRect() : rootFrame->GetRect();
|
||||
|
||||
nsLayoutUtils::GetFramesForArea(
|
||||
presShell->GetRootFrame(),
|
||||
scrollPort,
|
||||
frames,
|
||||
nsLayoutUtils::FrameForPointFlags::ONLY_VISIBLE);
|
||||
AccessibleHashtable inViewAccs;
|
||||
for (size_t i = 0; i < frames.Length(); i++) {
|
||||
nsIContent* content = frames.ElementAt(i)->GetContent();
|
||||
if (!content) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Accessible* visibleAcc = docAcc->GetAccessibleOrContainer(content);
|
||||
if (!visibleAcc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Accessible* acc = visibleAcc; acc && acc != docAcc->Parent(); acc = acc->Parent()) {
|
||||
if (inViewAccs.Contains(acc->UniqueID())) {
|
||||
break;
|
||||
}
|
||||
inViewAccs.Put(acc->UniqueID(), acc);
|
||||
}
|
||||
}
|
||||
|
||||
if (IPCAccessibilityActive()) {
|
||||
DocAccessibleChild* ipcDoc = docAcc->IPCDoc();
|
||||
nsTArray<BatchData> cacheData(inViewAccs.Count());
|
||||
for (auto iter = inViewAccs.Iter(); !iter.Done(); iter.Next()) {
|
||||
Accessible* accessible = iter.Data();
|
||||
auto uid = accessible->IsDoc() && accessible->AsDoc()->IPCDoc() ? 0
|
||||
: reinterpret_cast<uint64_t>(accessible->UniqueID());
|
||||
cacheData.AppendElement(BatchData(accessible->Document()->IPCDoc(),
|
||||
uid,
|
||||
accessible->State(),
|
||||
accessible->Bounds()));
|
||||
}
|
||||
|
||||
ipcDoc->SendBatch(eBatch_Viewport, cacheData);
|
||||
} else if (SessionAccessibility* sessionAcc = SessionAccessibility::GetInstanceFor(docAcc)) {
|
||||
nsTArray<AccessibleWrap*> accessibles(inViewAccs.Count());
|
||||
for (auto iter = inViewAccs.Iter(); !iter.Done(); iter.Next()) {
|
||||
accessibles.AppendElement(static_cast<AccessibleWrap*>(iter.Data().get()));
|
||||
}
|
||||
|
||||
sessionAcc->ReplaceViewportCache(accessibles);
|
||||
}
|
||||
|
||||
if (docAcc->mCacheRefreshTimer) {
|
||||
docAcc->mCacheRefreshTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessibleWrap::CacheViewport()
|
||||
{
|
||||
if (VirtualViewID() == kNoID && !mCacheRefreshTimer) {
|
||||
NS_NewTimerWithFuncCallback(getter_AddRefs(mCacheRefreshTimer),
|
||||
CacheViewportCallback,
|
||||
this,
|
||||
kCacheRefreshInterval,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
"a11y::DocAccessibleWrap::CacheViewport");
|
||||
if (mCacheRefreshTimer) {
|
||||
NS_ADDREF_THIS(); // Kung fu death grip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define mozilla_a11y_DocAccessibleWrap_h__
|
||||
|
||||
#include "DocAccessible.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
@ -17,6 +18,8 @@ public:
|
|||
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
|
||||
virtual ~DocAccessibleWrap();
|
||||
|
||||
virtual nsresult HandleAccEvent(AccEvent* aEvent) override;
|
||||
|
||||
/**
|
||||
* Manage the mapping from id to Accessible.
|
||||
*/
|
||||
|
@ -27,11 +30,24 @@ public:
|
|||
void RemoveID(uint32_t aID) { mIDToAccessibleMap.Remove(aID); }
|
||||
AccessibleWrap* GetAccessibleByID(int32_t aID) const;
|
||||
|
||||
enum {
|
||||
eBatch_Viewport = 0
|
||||
};
|
||||
|
||||
protected:
|
||||
/*
|
||||
* This provides a mapping from 32 bit id to accessible objects.
|
||||
*/
|
||||
nsDataHashtable<nsUint32HashKey, AccessibleWrap*> mIDToAccessibleMap;
|
||||
|
||||
virtual void DoInitialUpdate() override;
|
||||
|
||||
private:
|
||||
void CacheViewport();
|
||||
|
||||
static void CacheViewportCallback(nsITimer* aTimer, void* aDocAccParam);
|
||||
|
||||
nsCOMPtr<nsITimer> mCacheRefreshTimer;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "Platform.h"
|
||||
#include "ProxyAccessibleWrap.h"
|
||||
#include "DocAccessibleWrap.h"
|
||||
#include "SessionAccessibility.h"
|
||||
#include "mozilla/a11y/ProxyAccessible.h"
|
||||
#include "nsIAccessibleEvent.h"
|
||||
|
@ -198,3 +199,30 @@ a11y::ProxyScrollingEvent(ProxyAccessible* aTarget,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
a11y::ProxyBatch(ProxyAccessible* aDocument,
|
||||
const uint64_t aBatchType,
|
||||
const nsTArray<ProxyAccessible*>& aAccessibles,
|
||||
const nsTArray<BatchData>& aData)
|
||||
{
|
||||
SessionAccessibility* sessionAcc =
|
||||
SessionAccessibility::GetInstanceFor(aDocument);
|
||||
if (!sessionAcc) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<AccessibleWrap*> accWraps(aAccessibles.Length());
|
||||
for (size_t i = 0; i < aAccessibles.Length(); i++) {
|
||||
accWraps.AppendElement(WrapperFor(aAccessibles.ElementAt(i)));
|
||||
}
|
||||
|
||||
switch (aBatchType) {
|
||||
case DocAccessibleWrap::eBatch_Viewport:
|
||||
sessionAcc->ReplaceViewportCache(accWraps, aData);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown batch type.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "SessionAccessibility.h"
|
||||
#include "AndroidUiThread.h"
|
||||
#include "DocAccessibleParent.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "AccessibilityEvent.h"
|
||||
#include "HyperTextAccessible.h"
|
||||
|
@ -329,3 +330,21 @@ SessionAccessibility::SendSelectedEvent(AccessibleWrap* aAccessible)
|
|||
java::sdk::AccessibilityEvent::TYPE_VIEW_SELECTED,
|
||||
aAccessible->VirtualViewID(), aAccessible->AndroidClass(), nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
SessionAccessibility::ReplaceViewportCache(const nsTArray<AccessibleWrap*>& aAccessibles,
|
||||
const nsTArray<BatchData>& aData)
|
||||
{
|
||||
auto infos = jni::ObjectArray::New<java::GeckoBundle>(aAccessibles.Length());
|
||||
for (size_t i = 0; i < aAccessibles.Length(); i++) {
|
||||
AccessibleWrap* acc = aAccessibles.ElementAt(i);
|
||||
if (aData.Length() == aAccessibles.Length()) {
|
||||
const BatchData& data = aData.ElementAt(i);
|
||||
infos->SetElement(i, acc->ToSmallBundle(data.State(), data.Bounds()));
|
||||
} else {
|
||||
infos->SetElement(i, acc->ToSmallBundle());
|
||||
}
|
||||
}
|
||||
|
||||
mSessionAccessibility->ReplaceViewportCache(infos);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace a11y {
|
|||
class AccessibleWrap;
|
||||
class ProxyAccessible;
|
||||
class RootAccessibleWrap;
|
||||
class BatchData;
|
||||
|
||||
class SessionAccessibility final
|
||||
: public java::SessionAccessibility::NativeProvider::Natives<SessionAccessibility>
|
||||
|
@ -104,6 +105,10 @@ public:
|
|||
void SendWindowContentChangedEvent(AccessibleWrap* aAccessible);
|
||||
void SendWindowStateChangedEvent(AccessibleWrap* aAccessible);
|
||||
|
||||
// Cache methods
|
||||
void ReplaceViewportCache(const nsTArray<AccessibleWrap*>& aAccessibles,
|
||||
const nsTArray<BatchData>& aData = nsTArray<BatchData>());
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SessionAccessibility)
|
||||
|
||||
private:
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
#include <stdint.h>
|
||||
#include "nsStringFwd.h"
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include "nsTArray.h"
|
||||
#include "nsRect.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
|
@ -117,7 +122,15 @@ void ProxyVirtualCursorChangeEvent(ProxyAccessible* aTarget,
|
|||
void ProxyScrollingEvent(ProxyAccessible* aTarget, uint32_t aEventType,
|
||||
uint32_t aScrollX, uint32_t aScrollY,
|
||||
uint32_t aMaxScrollX, uint32_t aMaxScrollY);
|
||||
|
||||
class BatchData;
|
||||
|
||||
void ProxyBatch(ProxyAccessible* aDocument,
|
||||
const uint64_t aBatchType,
|
||||
const nsTArray<ProxyAccessible*>& aAccessibles,
|
||||
const nsTArray<BatchData>& aData);
|
||||
#endif
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -838,5 +838,27 @@ DocAccessibleParent::RecvFocusEvent(const uint64_t& aID,
|
|||
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
#if !defined(XP_WIN)
|
||||
mozilla::ipc::IPCResult
|
||||
DocAccessibleParent::RecvBatch(const uint64_t& aBatchType, nsTArray<BatchData>&& aData)
|
||||
{
|
||||
// Only do something in Android. We can't ifdef the entire protocol out in
|
||||
// the ipdl because it doesn't allow preprocessing.
|
||||
#if defined(ANDROID)
|
||||
nsTArray<ProxyAccessible*> proxies(aData.Length());
|
||||
for (size_t i = 0; i < aData.Length(); i++) {
|
||||
DocAccessibleParent* doc = static_cast<DocAccessibleParent*>(
|
||||
aData.ElementAt(i).Document().get_PDocAccessibleParent());
|
||||
MOZ_ASSERT(doc);
|
||||
ProxyAccessible* proxy = doc->GetAccessible(aData.ElementAt(i).ID());
|
||||
MOZ_ASSERT(proxy);
|
||||
proxies.AppendElement(proxy);
|
||||
}
|
||||
ProxyBatch(this, aBatchType, proxies, aData);
|
||||
#endif // defined(XP_WIN)
|
||||
return IPC_OK();
|
||||
}
|
||||
#endif // !defined(XP_WIN)
|
||||
|
||||
} // a11y
|
||||
} // mozilla
|
||||
|
|
|
@ -218,6 +218,10 @@ public:
|
|||
HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; }
|
||||
#endif
|
||||
|
||||
#if !defined(XP_WIN)
|
||||
virtual mozilla::ipc::IPCResult RecvBatch(const uint64_t& aBatchType, nsTArray<BatchData>&& aData) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
class ProxyEntry : public PLDHashEntryHdr
|
||||
|
|
|
@ -25,6 +25,19 @@ struct AccessibleData
|
|||
uint32_t Interfaces;
|
||||
};
|
||||
|
||||
union OriginDocument
|
||||
{
|
||||
PDocAccessible;
|
||||
};
|
||||
|
||||
struct BatchData
|
||||
{
|
||||
OriginDocument Document;
|
||||
uint64_t ID;
|
||||
uint64_t State;
|
||||
nsIntRect Bounds;
|
||||
};
|
||||
|
||||
struct ShowEventData
|
||||
{
|
||||
uint64_t ID;
|
||||
|
@ -82,6 +95,9 @@ parent:
|
|||
*/
|
||||
async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
|
||||
|
||||
// Android
|
||||
async Batch(uint64_t aBatchType, BatchData[] aData);
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
|
||||
|
|
|
@ -134,8 +134,15 @@ pref("app.update.download.promptMaxAttempts", 2);
|
|||
pref("app.update.elevation.promptMaxAttempts", 2);
|
||||
|
||||
// If set to true, the Update Service will automatically download updates if the
|
||||
// user can apply updates.
|
||||
// user can apply updates. This pref is no longer used on Windows, except as the
|
||||
// default value to migrate to the new location that this data is now stored
|
||||
// (which is in a file in the update directory). Because of this, this pref
|
||||
// should no longer be used directly. Instead,
|
||||
// nsIUpdateService::getAutoUpdateIsEnabled and
|
||||
// nsIUpdateService::setAutoUpdateIsEnabled should be used.
|
||||
#ifndef XP_WIN
|
||||
pref("app.update.auto", true);
|
||||
#endif
|
||||
|
||||
// If set to true, the Update Service will present no UI for any event.
|
||||
pref("app.update.silent", false);
|
||||
|
|
|
@ -40,6 +40,7 @@ function appUpdater(options = {}) {
|
|||
|
||||
this.options = options;
|
||||
this.updateDeck = document.getElementById("updateDeck");
|
||||
this.promiseAutoUpdateSetting = null;
|
||||
|
||||
// Hide the update deck when the update window is already open and it's not
|
||||
// already applied, to avoid syncing issues between them. Applied updates
|
||||
|
@ -81,6 +82,9 @@ function appUpdater(options = {}) {
|
|||
return;
|
||||
}
|
||||
|
||||
// We might need this value later, so start loading it from the disk now.
|
||||
this.promiseAutoUpdateSetting = this.aus.getAutoUpdateIsEnabled();
|
||||
|
||||
// That leaves the options
|
||||
// "Check for updates, but let me choose whether to install them", and
|
||||
// "Automatically install updates".
|
||||
|
@ -136,14 +140,6 @@ appUpdater.prototype =
|
|||
gAppUpdater.aus.canStageUpdates;
|
||||
},
|
||||
|
||||
// true when updating is automatic.
|
||||
get updateAuto() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref("app.update.auto");
|
||||
} catch (e) { }
|
||||
return true; // Firefox default is true
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the panel of the updateDeck.
|
||||
*
|
||||
|
@ -260,10 +256,16 @@ appUpdater.prototype =
|
|||
return;
|
||||
}
|
||||
|
||||
if (gAppUpdater.updateAuto) // automatically download and install
|
||||
gAppUpdater.startDownload();
|
||||
else // ask
|
||||
gAppUpdater.selectPanel("downloadAndInstall");
|
||||
if (this.promiseAutoUpdateSetting == null) {
|
||||
this.promiseAutoUpdateSetting = this.aus.getAutoUpdateIsEnabled();
|
||||
}
|
||||
this.promiseAutoUpdateSetting.then(updateAuto => {
|
||||
if (updateAuto) { // automatically download and install
|
||||
gAppUpdater.startDownload();
|
||||
} else { // ask
|
||||
gAppUpdater.selectPanel("downloadAndInstall");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -430,6 +430,7 @@ var ctrlTab = {
|
|||
onKeyDown(event) {
|
||||
if (event.keyCode != event.DOM_VK_TAB ||
|
||||
!event.ctrlKey ||
|
||||
!this.isOpen && event.shiftKey ||
|
||||
event.altKey ||
|
||||
event.metaKey) {
|
||||
return;
|
||||
|
@ -440,7 +441,7 @@ var ctrlTab = {
|
|||
|
||||
if (this.isOpen) {
|
||||
this.advanceFocus(!event.shiftKey);
|
||||
} else if (!event.shiftKey) {
|
||||
} else {
|
||||
let tabs = gBrowser.visibleTabs;
|
||||
if (tabs.length > 2) {
|
||||
this.open();
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
:root:-moz-lwtheme {
|
||||
--toolbar-bgcolor: rgba(255,255,255,.4);
|
||||
--toolbar-bgimage: none;
|
||||
--toolbar-color: inherit;
|
||||
--toolbar-color: var(--lwt-text-color, inherit);
|
||||
|
||||
background-color: var(--lwt-accent-color);
|
||||
color: var(--lwt-text-color);
|
||||
|
|
|
@ -4150,7 +4150,7 @@ const BrowserSearch = {
|
|||
*/
|
||||
recordSearchInTelemetry(engine, source, details = {}) {
|
||||
try {
|
||||
BrowserUsageTelemetry.recordSearch(engine, source, details);
|
||||
BrowserUsageTelemetry.recordSearch(gBrowser, engine, source, details);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
|
@ -4174,7 +4174,7 @@ const BrowserSearch = {
|
|||
recordOneoffSearchInTelemetry(engine, source, type, where) {
|
||||
try {
|
||||
const details = {type, isOneOff: true};
|
||||
BrowserUsageTelemetry.recordSearch(engine, source, details);
|
||||
BrowserUsageTelemetry.recordSearch(gBrowser, engine, source, details);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
persist="screenX screenY width height sizemode"
|
||||
#ifdef BROWSER_XHTML
|
||||
hidden="true"
|
||||
mozpersist=""
|
||||
#endif
|
||||
>
|
||||
|
||||
|
|
|
@ -46,7 +46,12 @@ add_task(async function shift_left_click_test() {
|
|||
is(win.gURLBar.textValue, TEST_VALUE, "New URL is loaded in new window");
|
||||
|
||||
// Cleanup.
|
||||
let ourWindowRefocusedPromise = Promise.all([
|
||||
BrowserTestUtils.waitForEvent(window, "activate"),
|
||||
BrowserTestUtils.waitForEvent(window, "focus", true),
|
||||
]);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
await ourWindowRefocusedPromise;
|
||||
});
|
||||
|
||||
add_task(async function right_click_test() {
|
||||
|
|
|
@ -11,6 +11,14 @@ var updateService = Cc["@mozilla.org/updates/update-service;1"].
|
|||
// policy is applied needs to occur in a different test since the policy does
|
||||
// not properly take effect unless it is applied during application startup.
|
||||
add_task(async function test_updates_pre_policy() {
|
||||
// Turn off automatic update before we set app.update.disabledForTesting to
|
||||
// false so that we don't cause an actual update.
|
||||
let originalUpdateAutoValue = await updateService.getAutoUpdateIsEnabled();
|
||||
await updateService.setAutoUpdateIsEnabled(false);
|
||||
registerCleanupFunction(async () => {
|
||||
await updateService.setAutoUpdateIsEnabled(originalUpdateAutoValue);
|
||||
});
|
||||
|
||||
await SpecialPowers.pushPrefEnv({"set": [["app.update.disabledForTesting", false]]});
|
||||
|
||||
is(Services.policies.isAllowed("appUpdate"), true,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[DEFAULT]
|
||||
prefs =
|
||||
app.update.disabledForTesting=false
|
||||
app.update.auto=true
|
||||
browser.policies.alternatePath='<test-root>/browser/components/enterprisepolicies/tests/browser/disable_app_update/config_disable_app_update.json'
|
||||
support-files =
|
||||
config_disable_app_update.json
|
||||
|
|
|
@ -76,17 +76,20 @@ this.search = class extends ExtensionAPI {
|
|||
postData: submission.postData,
|
||||
triggeringPrincipal: context.principal,
|
||||
};
|
||||
let tabbrowser;
|
||||
if (searchProperties.tabId === null) {
|
||||
let {gBrowser} = windowTracker.topWindow;
|
||||
let nativeTab = gBrowser.addTab(submission.uri.spec, options);
|
||||
if (!searchLoadInBackground) {
|
||||
gBrowser.selectedTab = nativeTab;
|
||||
}
|
||||
tabbrowser = gBrowser;
|
||||
} else {
|
||||
let tab = tabTracker.getTab(searchProperties.tabId);
|
||||
tab.linkedBrowser.loadURI(submission.uri.spec, options);
|
||||
tabbrowser = tab.linkedBrowser.getTabBrowser();
|
||||
}
|
||||
BrowserUsageTelemetry.recordSearch(engine, "webextension");
|
||||
BrowserUsageTelemetry.recordSearch(tabbrowser, engine, "webextension");
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -101,6 +101,11 @@
|
|||
"optional": true,
|
||||
"deprecated": "Unsupported on Firefox."
|
||||
},
|
||||
"encoding": {
|
||||
"type": "string",
|
||||
"optional": true,
|
||||
"description": "Encoding of the search term."
|
||||
},
|
||||
"is_default": {
|
||||
"type": "boolean",
|
||||
"optional": true,
|
||||
|
|
|
@ -271,7 +271,10 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
|
|||
const rows = Array.from(action.data.rows);
|
||||
section.rows.forEach((card, index) => {
|
||||
if (card.pinned) {
|
||||
rows.splice(index, 0, card);
|
||||
// Only add it if it's not already there.
|
||||
if (rows[index].guid !== card.guid) {
|
||||
rows.splice(index, 0, card);
|
||||
}
|
||||
}
|
||||
});
|
||||
return Object.assign({}, section, initialized, Object.assign({}, action.data, {rows}));
|
||||
|
|
|
@ -239,13 +239,14 @@ export class ASRouterAdmin extends React.PureComponent {
|
|||
renderTargetingParameters() {
|
||||
// There was no error and the result is truthy
|
||||
const success = this.state.evaluationStatus.success && !!this.state.evaluationStatus.result;
|
||||
const result = JSON.stringify(this.state.evaluationStatus.result, null, 2) || "(Empty result)";
|
||||
|
||||
return (<table><tbody>
|
||||
<tr><td><h2>Evaluate JEXL expression</h2></td></tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><textarea ref="expressionInput" rows="10" cols="60" placeholder="Evaluate JEXL expressions and mock parameters by changing their values below" /></p>
|
||||
<p>Status: <span ref="evaluationStatus">{success ? "✅" : "❌"}, Result: {JSON.stringify(this.state.evaluationStatus.result, null, 2)}</span></p>
|
||||
<p>Status: <span ref="evaluationStatus">{success ? "✅" : "❌"}, Result: {result}</span></p>
|
||||
</td>
|
||||
<td>
|
||||
<button className="ASRouterButton secondary" onClick={this.handleExpressionEval}>Evaluate</button>
|
||||
|
|
|
@ -2102,6 +2102,7 @@ class ASRouterAdmin extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCom
|
|||
renderTargetingParameters() {
|
||||
// There was no error and the result is truthy
|
||||
const success = this.state.evaluationStatus.success && !!this.state.evaluationStatus.result;
|
||||
const result = JSON.stringify(this.state.evaluationStatus.result, null, 2) || "(Empty result)";
|
||||
|
||||
return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
|
||||
"table",
|
||||
|
@ -2142,7 +2143,7 @@ class ASRouterAdmin extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCom
|
|||
{ ref: "evaluationStatus" },
|
||||
success ? "✅" : "❌",
|
||||
", Result: ",
|
||||
JSON.stringify(this.state.evaluationStatus.result, null, 2)
|
||||
result
|
||||
)
|
||||
)
|
||||
),
|
||||
|
@ -9385,7 +9386,10 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
|
|||
const rows = Array.from(action.data.rows);
|
||||
section.rows.forEach((card, index) => {
|
||||
if (card.pinned) {
|
||||
rows.splice(index, 0, card);
|
||||
// Only add it if it's not already there.
|
||||
if (rows[index].guid !== card.guid) {
|
||||
rows.splice(index, 0, card);
|
||||
}
|
||||
}
|
||||
});
|
||||
return Object.assign({}, section, initialized, Object.assign({}, action.data, { rows }));
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 1.6 KiB |
|
@ -773,8 +773,8 @@ CFR impression ping has two forms, in which the message_id could be of different
|
|||
"addon_version": "20180710100040",
|
||||
"locale": "en-US",
|
||||
"source": "CFR",
|
||||
// message_id could be the ID of the recommendation, such as "amazon_addon"
|
||||
"message_id": "amazon_addon",
|
||||
// message_id could be the ID of the recommendation, such as "wikipedia_addon"
|
||||
"message_id": "wikipedia_addon",
|
||||
"event": "IMPRESSION"
|
||||
}
|
||||
```
|
||||
|
@ -836,8 +836,8 @@ This reports the user's interaction with Activity Stream Router.
|
|||
"impression_id": "n/a",
|
||||
"locale": "en-US",
|
||||
"source": "CFR",
|
||||
// message_id could be the ID of the recommendation, such as "amazon_addon"
|
||||
"message_id": "amazon_addon",
|
||||
// message_id could be the ID of the recommendation, such as "wikipedia_addon"
|
||||
"message_id": "wikipedia_addon",
|
||||
"event": "[INSTALL | BLOCK | DISMISS | RATIONALE | LEARN_MORE | CLICK_DOORHANGER]"
|
||||
}
|
||||
```
|
||||
|
|
|
@ -561,7 +561,7 @@ class _ASRouter {
|
|||
try {
|
||||
evaluationStatus = {result: await ASRouterTargeting.isMatch(expression, context), success: true};
|
||||
} catch (e) {
|
||||
evaluationStatus = {result: e, success: false};
|
||||
evaluationStatus = {result: e.message, success: false};
|
||||
}
|
||||
|
||||
channel.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "ADMIN_SET_STATE", data: {...this.state, evaluationStatus}});
|
||||
|
|
|
@ -2,12 +2,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
const AMAZON_ASSISTANT_PARAMS = {
|
||||
existing_addons: ["abb@amazon.com", "{75c7fe97-5a90-4b54-9052-3534235eaf41}", "{ef34596e-1e43-4e84-b2ff-1e58e287e08d}", "{ea280feb-155a-492e-8016-ac96dd995f2c}", "izer@camelcamelcamel.com", "amptra@keepa.com", "pricealarm@icopron.ch", "{774f76c7-6807-481e-bf64-f9b7d5cda602}"],
|
||||
open_urls: ["smile.amazon.com", "www.audible.com", "www.amazon.com", "amazon.com", "audible.com"],
|
||||
sumo_path: "extensionrecommendations",
|
||||
min_frecency: 10000,
|
||||
};
|
||||
const FACEBOOK_CONTAINER_PARAMS = {
|
||||
existing_addons: ["@contain-facebook", "{bb1b80be-e6b3-40a1-9b6e-9d4073343f0b}", "{a50d61ca-d27b-437a-8b52-5fd801a0a88b}"],
|
||||
open_urls: ["www.facebook.com", "facebook.com"],
|
||||
|
@ -45,110 +39,6 @@ const REDDIT_ENHANCEMENT_PARAMS = {
|
|||
};
|
||||
|
||||
const CFR_MESSAGES = [
|
||||
{
|
||||
id: "AMAZON_ASSISTANT_1",
|
||||
template: "cfr_doorhanger",
|
||||
content: {
|
||||
bucket_id: "CFR_M1",
|
||||
notification_text: {string_id: "cfr-doorhanger-extension-notification"},
|
||||
heading_text: {string_id: "cfr-doorhanger-extension-heading"},
|
||||
info_icon: {
|
||||
label: {string_id: "cfr-doorhanger-extension-sumo-link"},
|
||||
sumo_path: AMAZON_ASSISTANT_PARAMS.sumo_path,
|
||||
},
|
||||
addon: {
|
||||
id: "337359",
|
||||
title: "Amazon Assistant",
|
||||
icon: "resource://activity-stream/data/content/assets/cfr_amazon_assistant.png",
|
||||
rating: 3.3,
|
||||
users: 443046,
|
||||
author: "Amazon",
|
||||
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/amazon-browser-bar/",
|
||||
},
|
||||
text: "Amazon Assistant helps you make better shopping decisions by showing product comparisons at thousands of retail sites.",
|
||||
buttons: {
|
||||
primary: {
|
||||
label: {string_id: "cfr-doorhanger-extension-ok-button"},
|
||||
action: {
|
||||
type: "INSTALL_ADDON_FROM_URL",
|
||||
data: {url: null},
|
||||
},
|
||||
},
|
||||
secondary: [{
|
||||
label: {string_id: "cfr-doorhanger-extension-cancel-button"},
|
||||
action: {type: "CANCEL"},
|
||||
}, {
|
||||
label: {string_id: "cfr-doorhanger-extension-never-show-recommendation"},
|
||||
}, {
|
||||
label: {string_id: "cfr-doorhanger-extension-manage-settings-button"},
|
||||
action: {
|
||||
type: "OPEN_PREFERENCES_PAGE",
|
||||
data: {category: "general-cfr", origin: "CFR"},
|
||||
},
|
||||
}],
|
||||
},
|
||||
},
|
||||
frequency: {lifetime: 1},
|
||||
targeting: `
|
||||
localeLanguageCode == "en" &&
|
||||
(providerCohorts.cfr == "one_per_day_amazon") &&
|
||||
(xpinstallEnabled == true) &&
|
||||
(${JSON.stringify(AMAZON_ASSISTANT_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
||||
(${JSON.stringify(AMAZON_ASSISTANT_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${AMAZON_ASSISTANT_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||
trigger: {id: "openURL", params: AMAZON_ASSISTANT_PARAMS.open_urls},
|
||||
},
|
||||
{
|
||||
id: "AMAZON_ASSISTANT_3",
|
||||
template: "cfr_doorhanger",
|
||||
content: {
|
||||
bucket_id: "CFR_M1",
|
||||
notification_text: {string_id: "cfr-doorhanger-extension-notification"},
|
||||
heading_text: {string_id: "cfr-doorhanger-extension-heading"},
|
||||
info_icon: {
|
||||
label: {string_id: "cfr-doorhanger-extension-sumo-link"},
|
||||
sumo_path: AMAZON_ASSISTANT_PARAMS.sumo_path,
|
||||
},
|
||||
addon: {
|
||||
id: "337359",
|
||||
title: "Amazon Assistant",
|
||||
icon: "resource://activity-stream/data/content/assets/cfr_amazon_assistant.png",
|
||||
rating: 3.3,
|
||||
users: 443046,
|
||||
author: "Amazon",
|
||||
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/amazon-browser-bar/",
|
||||
},
|
||||
text: "Amazon Assistant helps you make better shopping decisions by showing product comparisons at thousands of retail sites.",
|
||||
buttons: {
|
||||
primary: {
|
||||
label: {string_id: "cfr-doorhanger-extension-ok-button"},
|
||||
action: {
|
||||
type: "INSTALL_ADDON_FROM_URL",
|
||||
data: {url: null},
|
||||
},
|
||||
},
|
||||
secondary: [{
|
||||
label: {string_id: "cfr-doorhanger-extension-cancel-button"},
|
||||
action: {type: "CANCEL"},
|
||||
}, {
|
||||
label: {string_id: "cfr-doorhanger-extension-never-show-recommendation"},
|
||||
}, {
|
||||
label: {string_id: "cfr-doorhanger-extension-manage-settings-button"},
|
||||
action: {
|
||||
type: "OPEN_PREFERENCES_PAGE",
|
||||
data: {category: "general-cfr", origin: "CFR"},
|
||||
},
|
||||
}],
|
||||
},
|
||||
},
|
||||
frequency: {lifetime: 3},
|
||||
targeting: `
|
||||
localeLanguageCode == "en" &&
|
||||
(providerCohorts.cfr == "three_per_day_amazon") &&
|
||||
(xpinstallEnabled == true) &&
|
||||
(${JSON.stringify(AMAZON_ASSISTANT_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
||||
(${JSON.stringify(AMAZON_ASSISTANT_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${AMAZON_ASSISTANT_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||
trigger: {id: "openURL", params: AMAZON_ASSISTANT_PARAMS.open_urls},
|
||||
},
|
||||
{
|
||||
id: "FACEBOOK_CONTAINER_1",
|
||||
template: "cfr_doorhanger",
|
||||
|
|
|
@ -7680,10 +7680,9 @@
|
|||
}
|
||||
},
|
||||
"merge": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz",
|
||||
"integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=",
|
||||
"dev": true
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz",
|
||||
"integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ=="
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "2.3.11",
|
||||
|
@ -10250,7 +10249,7 @@
|
|||
"known-css-properties": "0.3.0",
|
||||
"lodash.capitalize": "4.2.1",
|
||||
"lodash.kebabcase": "4.1.1",
|
||||
"merge": "1.2.0",
|
||||
"merge": "^1.2.0",
|
||||
"path-is-absolute": "1.0.1",
|
||||
"util": "0.10.3"
|
||||
},
|
||||
|
|
|
@ -110,6 +110,10 @@
|
|||
"buildmc:copy": "rsync --exclude-from .mcignore -a . $npm_package_config_mc_dir/browser/components/newtab/",
|
||||
"buildmc:stringsExport": "cp $npm_package_config_locales_dir/$npm_package_config_default_locale/strings.properties $npm_package_config_mc_dir/browser/locales/$npm_package_config_default_locale/chrome/browser/activity-stream/newtab.properties",
|
||||
"buildmc:copyPingCentre": "cpx \"ping-centre/PingCentre.jsm\" $npm_package_config_mc_dir/browser/modules",
|
||||
"builduplift": "npm-run-all builduplift:*",
|
||||
"prebuilduplift": "npm run prebuildmc",
|
||||
"builduplift:bundle": "npm run bundle",
|
||||
"builduplift:copy": "npm run buildmc:copy",
|
||||
"buildlibrary": "npm-run-all buildlibrary:*",
|
||||
"buildlibrary:webpack": "webpack --config webpack.aboutlibrary.config.js",
|
||||
"buildlibrary:css": "node-sass --source-map true --source-map-contents content-src/aboutlibrary -o aboutlibrary/content",
|
||||
|
|
|
@ -10,8 +10,8 @@ const REGULAR_IDS = [
|
|||
];
|
||||
|
||||
describe("CFRMessageProvider", () => {
|
||||
it("should have a total of 12 messages", () => {
|
||||
assert.lengthOf(messages, 12);
|
||||
it("should have a total of 10 messages", () => {
|
||||
assert.lengthOf(messages, 10);
|
||||
});
|
||||
it("should two variants for each of the five regular addons", () => {
|
||||
for (const id of REGULAR_IDS) {
|
||||
|
@ -28,19 +28,6 @@ describe("CFRMessageProvider", () => {
|
|||
assert.deepEqual(cohort1.content, cohort3.content, "cohorts should have the same content");
|
||||
}
|
||||
});
|
||||
it("should have the two amazon cohorts", () => {
|
||||
const cohort1 = messages.find(msg => msg.id === `AMAZON_ASSISTANT_1`);
|
||||
const cohort3 = messages.find(msg => msg.id === `AMAZON_ASSISTANT_3`);
|
||||
assert.deepEqual(cohort1.content, cohort3.content, "cohorts should have the same content");
|
||||
|
||||
assert.ok(cohort1, `contains one day cohort for amazon`);
|
||||
assert.deepEqual(cohort1.frequency, {lifetime: 1}, "one day cohort has the right frequency cap");
|
||||
assert.include(cohort1.targeting, `(providerCohorts.cfr == "one_per_day_amazon"`);
|
||||
|
||||
assert.ok(cohort3, `contains three day cohort for amazon`);
|
||||
assert.deepEqual(cohort3.frequency, {lifetime: 3}, "three day cohort has the right frequency cap");
|
||||
assert.include(cohort3.targeting, `(providerCohorts.cfr == "three_per_day_amazon")`);
|
||||
});
|
||||
it("should always have xpinstallEnabled as targeting if it is an addon", () => {
|
||||
for (const message of messages) {
|
||||
// Ensure that the CFR messages that are recommending an addon have this targeting.
|
||||
|
|
|
@ -338,7 +338,12 @@ describe("Reducers", () => {
|
|||
let updatedSection = newState.find(section => section.id === "foo_bar_2");
|
||||
assert.deepEqual(updatedSection.rows, [ROW]);
|
||||
|
||||
const PINNED_ROW = {id: "pinned", pinned: true};
|
||||
const PINNED_ROW = {id: "pinned", pinned: true, guid: "pinned"};
|
||||
newState = Sections(newState, {type: at.SECTION_UPDATE, data: Object.assign({rows: [PINNED_ROW]}, {id: "foo_bar_2"})});
|
||||
updatedSection = newState.find(section => section.id === "foo_bar_2");
|
||||
assert.deepEqual(updatedSection.rows, [PINNED_ROW]);
|
||||
|
||||
// Updating the section again should not duplicate pinned cards
|
||||
newState = Sections(newState, {type: at.SECTION_UPDATE, data: Object.assign({rows: [PINNED_ROW]}, {id: "foo_bar_2"})});
|
||||
updatedSection = newState.find(section => section.id === "foo_bar_2");
|
||||
assert.deepEqual(updatedSection.rows, [PINNED_ROW]);
|
||||
|
|
|
@ -27,6 +27,12 @@ scripts:
|
|||
stringsExport: cp $npm_package_config_locales_dir/$npm_package_config_default_locale/strings.properties $npm_package_config_mc_dir/browser/locales/$npm_package_config_default_locale/chrome/browser/activity-stream/newtab.properties
|
||||
copyPingCentre: cpx "ping-centre/PingCentre.jsm" $npm_package_config_mc_dir/browser/modules
|
||||
|
||||
# builduplift: Build and export to mozilla central for uplifts without exporting strings to browser/locales
|
||||
builduplift:
|
||||
pre: =>prebuildmc
|
||||
bundle: => bundle
|
||||
copy: =>buildmc:copy
|
||||
|
||||
# buildlibrary: Export about:library code to mozilla-central - intentionally not included in buildmc for now
|
||||
buildlibrary:
|
||||
webpack: webpack --config webpack.aboutlibrary.config.js
|
||||
|
|
|
@ -20,6 +20,7 @@ ChromeUtils.defineModuleGetter(this, "CloudStorage",
|
|||
"resource://gre/modules/CloudStorage.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetters(this, {
|
||||
gAUS: ["@mozilla.org/updates/update-service;1", "nsIApplicationUpdateService"],
|
||||
gHandlerService: ["@mozilla.org/uriloader/handler-service;1", "nsIHandlerService"],
|
||||
gMIMEService: ["@mozilla.org/mime;1", "nsIMIMEService"],
|
||||
});
|
||||
|
@ -43,6 +44,8 @@ const PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS =
|
|||
// Strings to identify ExtensionSettingsStore overrides
|
||||
const CONTAINERS_KEY = "privacy.containers";
|
||||
|
||||
const AUTO_UPDATE_CHANGED_TOPIC = "auto-update-config-change";
|
||||
|
||||
// The nsHandlerInfoAction enumeration values in nsIHandlerInfo identify
|
||||
// the actions the application can take with content of various types.
|
||||
// But since nsIHandlerInfo doesn't support plugins, there's no value
|
||||
|
@ -175,7 +178,6 @@ if (AppConstants.platform === "win") {
|
|||
|
||||
if (AppConstants.MOZ_UPDATER) {
|
||||
Preferences.addAll([
|
||||
{ id: "app.update.auto", type: "bool" },
|
||||
{ id: "app.update.disable_button.showUpdateHistory", type: "bool" },
|
||||
]);
|
||||
|
||||
|
@ -481,6 +483,14 @@ var gMainPane = {
|
|||
if (AppConstants.MOZ_MAINTENANCE_SERVICE) {
|
||||
document.getElementById("useService").hidden = true;
|
||||
}
|
||||
} else {
|
||||
// Start with no option selected since we are still reading the value
|
||||
document.getElementById("autoDesktop").removeAttribute("selected");
|
||||
document.getElementById("manualDesktop").removeAttribute("selected");
|
||||
// Start reading the correct value from the disk
|
||||
this.updateReadPrefs();
|
||||
setEventListener("updateRadioGroup", "command",
|
||||
gMainPane.updateWritePrefs);
|
||||
}
|
||||
|
||||
if (AppConstants.MOZ_MAINTENANCE_SERVICE) {
|
||||
|
@ -509,6 +519,7 @@ var gMainPane = {
|
|||
// the view when they change.
|
||||
Services.prefs.addObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
|
||||
Services.prefs.addObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
|
||||
Services.obs.addObserver(this, AUTO_UPDATE_CHANGED_TOPIC);
|
||||
|
||||
setEventListener("filter", "command", gMainPane.filter);
|
||||
setEventListener("typeColumn", "click", gMainPane.sort);
|
||||
|
@ -1272,6 +1283,57 @@ var gMainPane = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Selects the correct item in the update radio group
|
||||
*/
|
||||
async updateReadPrefs() {
|
||||
if (AppConstants.MOZ_UPDATER &&
|
||||
(!Services.policies || Services.policies.isAllowed("appUpdate"))) {
|
||||
let radiogroup = document.getElementById("updateRadioGroup");
|
||||
radiogroup.disabled = true;
|
||||
try {
|
||||
let enabled = await gAUS.getAutoUpdateIsEnabled();
|
||||
radiogroup.value = enabled;
|
||||
radiogroup.disabled = false;
|
||||
} catch (error) {
|
||||
Cu.reportError(error);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes the value of the update radio group to the disk
|
||||
*/
|
||||
async updateWritePrefs() {
|
||||
if (AppConstants.MOZ_UPDATER &&
|
||||
(!Services.policies || Services.policies.isAllowed("appUpdate"))) {
|
||||
let radiogroup = document.getElementById("updateRadioGroup");
|
||||
let updateAutoValue = (radiogroup.value == "true");
|
||||
radiogroup.disabled = true;
|
||||
try {
|
||||
await gAUS.setAutoUpdateIsEnabled(updateAutoValue);
|
||||
radiogroup.disabled = false;
|
||||
} catch (error) {
|
||||
Cu.reportError(error);
|
||||
await this.updateReadPrefs();
|
||||
await this.reportUpdatePrefWriteError(error);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async reportUpdatePrefWriteError(error) {
|
||||
let [title, message] = await document.l10n.formatValues([
|
||||
{id: "update-pref-write-failure-title"},
|
||||
{id: "update-pref-write-failure-message", args: {path: error.path}},
|
||||
]);
|
||||
|
||||
// Set up the Ok Button
|
||||
let buttonFlags = (Services.prompt.BUTTON_POS_0 *
|
||||
Services.prompt.BUTTON_TITLE_OK);
|
||||
Services.prompt.confirmEx(window, title, message, buttonFlags,
|
||||
null, null, null, null, {});
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the history of installed updates.
|
||||
*/
|
||||
|
@ -1285,6 +1347,8 @@ var gMainPane = {
|
|||
Services.prefs.removeObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
|
||||
|
||||
Services.prefs.removeObserver(PREF_CONTAINERS_EXTENSION, this);
|
||||
|
||||
Services.obs.removeObserver(this, AUTO_UPDATE_CHANGED_TOPIC);
|
||||
},
|
||||
|
||||
|
||||
|
@ -1315,6 +1379,11 @@ var gMainPane = {
|
|||
// the view when any of them changes.
|
||||
this._rebuildView();
|
||||
}
|
||||
} else if (aTopic == AUTO_UPDATE_CHANGED_TOPIC) {
|
||||
if (aData != "true" && aData != "false") {
|
||||
throw new Error("Invalid preference value for app.update.auto");
|
||||
}
|
||||
document.getElementById("updateRadioGroup").value = aData;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -558,11 +558,12 @@
|
|||
|
||||
#ifdef MOZ_UPDATER
|
||||
<description id="updateAllowDescription" data-l10n-id="update-application-allow-description"></description>
|
||||
<radiogroup id="updateRadioGroup" preference="app.update.auto">
|
||||
<radiogroup id="updateRadioGroup">
|
||||
<radio id="autoDesktop"
|
||||
value="true"
|
||||
data-l10n-id="update-application-auto"/>
|
||||
<radio value="false"
|
||||
<radio id="manualDesktop"
|
||||
value="false"
|
||||
data-l10n-id="update-application-check-choose"/>
|
||||
</radiogroup>
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
|
|
|
@ -360,6 +360,12 @@ update-enable-search-update =
|
|||
.label = Automatically update search engines
|
||||
.accesskey = e
|
||||
|
||||
update-pref-write-failure-title = Write Failure
|
||||
|
||||
# Variables:
|
||||
# $path (String) - Path to the configuration file
|
||||
update-pref-write-failure-message = Unable to save preference. Could not write to file: { $path }
|
||||
|
||||
## General Section - Performance
|
||||
|
||||
performance-title = Performance
|
||||
|
|
|
@ -117,6 +117,11 @@ function getSearchEngineId(engine) {
|
|||
return "other";
|
||||
}
|
||||
|
||||
function shouldRecordSearchCount(tabbrowser) {
|
||||
return !PrivateBrowsingUtils.isWindowPrivate(tabbrowser.ownerGlobal) ||
|
||||
!Services.prefs.getBoolPref("browser.engagement.search_counts.pbm", false);
|
||||
}
|
||||
|
||||
let URICountListener = {
|
||||
// A set containing the visited domains, see bug 1271310.
|
||||
_domainSet: new Set(),
|
||||
|
@ -200,7 +205,9 @@ let URICountListener = {
|
|||
return;
|
||||
}
|
||||
|
||||
Services.search.recordSearchURLTelemetry(uriSpec);
|
||||
if (shouldRecordSearchCount(browser.getTabBrowser())) {
|
||||
Services.search.recordSearchURLTelemetry(uriSpec);
|
||||
}
|
||||
|
||||
if (!shouldCountURI) {
|
||||
return;
|
||||
|
@ -400,6 +407,8 @@ let BrowserUsageTelemetry = {
|
|||
* Telemetry records only search counts per engine and action origin, but
|
||||
* nothing pertaining to the search contents themselves.
|
||||
*
|
||||
* @param {tabbrowser} tabbrowser
|
||||
* The tabbrowser where the search was loaded.
|
||||
* @param {nsISearchEngine} engine
|
||||
* The engine handling the search.
|
||||
* @param {String} source
|
||||
|
@ -416,7 +425,11 @@ let BrowserUsageTelemetry = {
|
|||
* The object describing the event that triggered the search.
|
||||
* @throws if source is not in the known sources list.
|
||||
*/
|
||||
recordSearch(engine, source, details = {}) {
|
||||
recordSearch(tabbrowser, engine, source, details = {}) {
|
||||
if (!shouldRecordSearchCount(tabbrowser)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isOneOff = !!details.isOneOff;
|
||||
const countId = getSearchEngineId(engine) + "." + source;
|
||||
|
||||
|
|
|
@ -574,3 +574,122 @@ add_task(async function test_suggestion_rightclick() {
|
|||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_privateWindow() {
|
||||
// Mock the search service's search provider info so that its
|
||||
// recordSearchURLTelemetry() function adds the in-content SEARCH_COUNTS
|
||||
// telemetry for our test engine.
|
||||
Services.search.QueryInterface(Ci.nsIObserver).observe(
|
||||
null,
|
||||
"test:setSearchProviderInfo",
|
||||
JSON.stringify({
|
||||
"example": {
|
||||
"regexp": "^http://example\\.com/",
|
||||
"queryParam": "q",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
let search_hist = getAndClearKeyedHistogram("SEARCH_COUNTS");
|
||||
|
||||
// First, do a bunch of searches in a private window.
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow({ private: true });
|
||||
|
||||
info("Search in a private window and the pref does not exist");
|
||||
let p = BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
await searchInAwesomebar("query", win);
|
||||
EventUtils.synthesizeKey("KEY_Enter", undefined, win);
|
||||
await p;
|
||||
|
||||
// SEARCH_COUNTS should be incremented.
|
||||
checkKeyedHistogram(search_hist, "other-MozSearch.urlbar", 1);
|
||||
checkKeyedHistogram(search_hist, "example.in-content:organic:none", 1);
|
||||
|
||||
info("Search again in a private window after setting the pref to true");
|
||||
Services.prefs.setBoolPref("browser.engagement.search_counts.pbm", true);
|
||||
p = BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
await searchInAwesomebar("another query", win);
|
||||
EventUtils.synthesizeKey("KEY_Enter", undefined, win);
|
||||
await p;
|
||||
|
||||
// SEARCH_COUNTS should *not* be incremented.
|
||||
checkKeyedHistogram(search_hist, "other-MozSearch.urlbar", 1);
|
||||
checkKeyedHistogram(search_hist, "example.in-content:organic:none", 1);
|
||||
|
||||
info("Search again in a private window after setting the pref to false");
|
||||
Services.prefs.setBoolPref("browser.engagement.search_counts.pbm", false);
|
||||
p = BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
await searchInAwesomebar("another query", win);
|
||||
EventUtils.synthesizeKey("KEY_Enter", undefined, win);
|
||||
await p;
|
||||
|
||||
// SEARCH_COUNTS should be incremented.
|
||||
checkKeyedHistogram(search_hist, "other-MozSearch.urlbar", 2);
|
||||
checkKeyedHistogram(search_hist, "example.in-content:organic:none", 2);
|
||||
|
||||
info("Search again in a private window after clearing the pref");
|
||||
Services.prefs.clearUserPref("browser.engagement.search_counts.pbm");
|
||||
p = BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
await searchInAwesomebar("another query", win);
|
||||
EventUtils.synthesizeKey("KEY_Enter", undefined, win);
|
||||
await p;
|
||||
|
||||
// SEARCH_COUNTS should be incremented.
|
||||
checkKeyedHistogram(search_hist, "other-MozSearch.urlbar", 3);
|
||||
checkKeyedHistogram(search_hist, "example.in-content:organic:none", 3);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
// Now, do a bunch of searches in a non-private window. Telemetry should
|
||||
// always be recorded regardless of the pref's value.
|
||||
win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
info("Search in a non-private window and the pref does not exist");
|
||||
p = BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
await searchInAwesomebar("query", win);
|
||||
EventUtils.synthesizeKey("KEY_Enter", undefined, win);
|
||||
await p;
|
||||
|
||||
// SEARCH_COUNTS should be incremented.
|
||||
checkKeyedHistogram(search_hist, "other-MozSearch.urlbar", 4);
|
||||
checkKeyedHistogram(search_hist, "example.in-content:organic:none", 4);
|
||||
|
||||
info("Search again in a non-private window after setting the pref to true");
|
||||
Services.prefs.setBoolPref("browser.engagement.search_counts.pbm", true);
|
||||
p = BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
await searchInAwesomebar("another query", win);
|
||||
EventUtils.synthesizeKey("KEY_Enter", undefined, win);
|
||||
await p;
|
||||
|
||||
// SEARCH_COUNTS should be incremented.
|
||||
checkKeyedHistogram(search_hist, "other-MozSearch.urlbar", 5);
|
||||
checkKeyedHistogram(search_hist, "example.in-content:organic:none", 5);
|
||||
|
||||
info("Search again in a non-private window after setting the pref to false");
|
||||
Services.prefs.setBoolPref("browser.engagement.search_counts.pbm", false);
|
||||
p = BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
await searchInAwesomebar("another query", win);
|
||||
EventUtils.synthesizeKey("KEY_Enter", undefined, win);
|
||||
await p;
|
||||
|
||||
// SEARCH_COUNTS should be incremented.
|
||||
checkKeyedHistogram(search_hist, "other-MozSearch.urlbar", 6);
|
||||
checkKeyedHistogram(search_hist, "example.in-content:organic:none", 6);
|
||||
|
||||
info("Search again in a non-private window after clearing the pref");
|
||||
Services.prefs.clearUserPref("browser.engagement.search_counts.pbm");
|
||||
p = BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
await searchInAwesomebar("another query", win);
|
||||
EventUtils.synthesizeKey("KEY_Enter", undefined, win);
|
||||
await p;
|
||||
|
||||
// SEARCH_COUNTS should be incremented.
|
||||
checkKeyedHistogram(search_hist, "other-MozSearch.urlbar", 7);
|
||||
checkKeyedHistogram(search_hist, "example.in-content:organic:none", 7);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
// Reset the search provider info.
|
||||
Services.search.QueryInterface(Ci.nsIObserver)
|
||||
.observe(null, "test:setSearchProviderInfo", "");
|
||||
});
|
||||
|
|
|
@ -14,3 +14,7 @@
|
|||
outline: 1px -moz-dialogtext dotted;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
.tracking-protection-button > .button-box > .button-icon {
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
|
|
|
@ -201,7 +201,7 @@
|
|||
|
||||
#cfr-notification-header-link {
|
||||
margin: 7px;
|
||||
color: var(--lwt-text-color);
|
||||
color: inherit;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
|
@ -258,7 +258,7 @@
|
|||
-moz-context-properties: fill, fill-opacity;
|
||||
background-image: var(--cfr-notification-footer-star);
|
||||
background-size: 17px;
|
||||
fill: var(--lwt-text-color);
|
||||
fill: currentColor;
|
||||
fill-opacity: 0.7;
|
||||
height: 16px;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
there are overrides for each platform in their compacttheme.css files. */
|
||||
|
||||
:root:-moz-lwtheme {
|
||||
--toolbar-color: var(--lwt-text-color);
|
||||
--toolbar-non-lwt-bgcolor: var(--toolbar-bgcolor);
|
||||
--toolbar-non-lwt-textcolor: var(--lwt-text-color);
|
||||
--toolbar-non-lwt-bgimage: none;
|
||||
|
|
|
@ -468,6 +468,7 @@ description#identity-popup-content-verifier,
|
|||
display: none;
|
||||
height: 32px;
|
||||
background-color: var(--arrowpanel-dimmed);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.tracking-protection-button:hover {
|
||||
|
|
|
@ -4,3 +4,6 @@
|
|||
|
||||
%include ../../shared/controlcenter/panel.inc.css
|
||||
|
||||
.tracking-protection-button > .button-box > .button-icon {
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
|
|
Двоичные данные
build/pgo/certs/cert9.db
Двоичные данные
build/pgo/certs/cert9.db
Двоичный файл не отображается.
Двоичные данные
build/pgo/certs/key4.db
Двоичные данные
build/pgo/certs/key4.db
Двоичный файл не отображается.
Двоичные данные
build/pgo/certs/mochitest.client
Двоичные данные
build/pgo/certs/mochitest.client
Двоичный файл не отображается.
|
@ -173,6 +173,7 @@ http://unwanted.example.com:80
|
|||
http://tracking.example.com:80
|
||||
http://not-tracking.example.com:80
|
||||
http://tracking.example.org:80
|
||||
http://another-tracking.example.net:80
|
||||
http://itisatracker.org:80
|
||||
http://trackertest.org:80
|
||||
|
||||
|
@ -181,6 +182,7 @@ https://unwanted.example.com:443
|
|||
https://tracking.example.com:443
|
||||
https://not-tracking.example.com:443
|
||||
https://tracking.example.org:443
|
||||
https://another-tracking.example.net:443
|
||||
|
||||
#
|
||||
# Used while testing flash blocking (Bug 1307604)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/******************************************************************************
|
||||
** This file is an amalgamation of many separate C source files from SQLite
|
||||
** version 3.25.1. By combining all the individual C code files into this
|
||||
** version 3.25.3. By combining all the individual C code files into this
|
||||
** single large file, the entire code can be compiled as a single translation
|
||||
** unit. This allows many compilers to do optimizations that would not be
|
||||
** possible if the files were compiled separately. Performance improvements
|
||||
|
@ -1156,9 +1156,9 @@ extern "C" {
|
|||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.25.1"
|
||||
#define SQLITE_VERSION_NUMBER 3025001
|
||||
#define SQLITE_SOURCE_ID "2018-09-18 20:20:44 2ac9003de44da7dafa3fbb1915ac5725a9275c86bf2f3b7aa19321bf1460b386"
|
||||
#define SQLITE_VERSION "3.25.3"
|
||||
#define SQLITE_VERSION_NUMBER 3025003
|
||||
#define SQLITE_SOURCE_ID "2018-11-05 20:37:38 89e099fbe5e13c33e683bef07361231ca525b88f7907be7092058007b75036f2"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
|
@ -16269,6 +16269,7 @@ struct sqlite3 {
|
|||
#define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee*/
|
||||
#define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */
|
||||
#define SQLITE_ResetDatabase 0x02000000 /* Reset the database */
|
||||
#define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */
|
||||
|
||||
/* Flags used only if debugging */
|
||||
#ifdef SQLITE_DEBUG
|
||||
|
@ -17911,6 +17912,7 @@ struct AuthContext {
|
|||
*/
|
||||
#define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */
|
||||
/* Also used in P2 (not P5) of OP_Delete */
|
||||
#define OPFLAG_NOCHNG 0x01 /* OP_VColumn nochange for UPDATE */
|
||||
#define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */
|
||||
#define OPFLAG_LASTROWID 0x20 /* Set to update db->lastRowid */
|
||||
#define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */
|
||||
|
@ -32619,7 +32621,11 @@ static struct unix_syscall {
|
|||
#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
|
||||
|
||||
#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
# ifdef __ANDROID__
|
||||
{ "ioctl", (sqlite3_syscall_ptr)(int(*)(int, int, ...))ioctl, 0 },
|
||||
# else
|
||||
{ "ioctl", (sqlite3_syscall_ptr)ioctl, 0 },
|
||||
# endif
|
||||
#else
|
||||
{ "ioctl", (sqlite3_syscall_ptr)0, 0 },
|
||||
#endif
|
||||
|
@ -80098,7 +80104,9 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
|||
(void)getVarint32((u8*)m.z, szHdr);
|
||||
testcase( szHdr==3 );
|
||||
testcase( szHdr==m.n );
|
||||
if( unlikely(szHdr<3 || (int)szHdr>m.n) ){
|
||||
testcase( szHdr>0x7fffffff );
|
||||
assert( m.n>=0 );
|
||||
if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){
|
||||
goto idx_rowid_corruption;
|
||||
}
|
||||
|
||||
|
@ -89611,10 +89619,11 @@ case OP_VFilter: { /* jump */
|
|||
**
|
||||
** If the VColumn opcode is being used to fetch the value of
|
||||
** an unchanging column during an UPDATE operation, then the P5
|
||||
** value is 1. Otherwise, P5 is 0. The P5 value is returned
|
||||
** by sqlite3_vtab_nochange() routine and can be used
|
||||
** by virtual table implementations to return special "no-change"
|
||||
** marks which can be more efficient, depending on the virtual table.
|
||||
** value is OPFLAG_NOCHNG. This will cause the sqlite3_vtab_nochange()
|
||||
** function to return true inside the xColumn method of the virtual
|
||||
** table implementation. The P5 column might also contain other
|
||||
** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are
|
||||
** unused by OP_VColumn.
|
||||
*/
|
||||
case OP_VColumn: {
|
||||
sqlite3_vtab *pVtab;
|
||||
|
@ -89636,7 +89645,8 @@ case OP_VColumn: {
|
|||
assert( pModule->xColumn );
|
||||
memset(&sContext, 0, sizeof(sContext));
|
||||
sContext.pOut = pDest;
|
||||
if( pOp->p5 ){
|
||||
testcase( (pOp->p5 & OPFLAG_NOCHNG)==0 && pOp->p5!=0 );
|
||||
if( pOp->p5 & OPFLAG_NOCHNG ){
|
||||
sqlite3VdbeMemSetNull(pDest);
|
||||
pDest->flags = MEM_Null|MEM_Zero;
|
||||
pDest->u.nZero = 0;
|
||||
|
@ -89713,7 +89723,10 @@ case OP_VNext: { /* jump */
|
|||
case OP_VRename: {
|
||||
sqlite3_vtab *pVtab;
|
||||
Mem *pName;
|
||||
|
||||
int isLegacy;
|
||||
|
||||
isLegacy = (db->flags & SQLITE_LegacyAlter);
|
||||
db->flags |= SQLITE_LegacyAlter;
|
||||
pVtab = pOp->p4.pVtab->pVtab;
|
||||
pName = &aMem[pOp->p1];
|
||||
assert( pVtab->pModule->xRename );
|
||||
|
@ -89727,6 +89740,7 @@ case OP_VRename: {
|
|||
rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
rc = pVtab->pModule->xRename(pVtab, pName->z);
|
||||
if( isLegacy==0 ) db->flags &= ~SQLITE_LegacyAlter;
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
p->expired = 0;
|
||||
if( rc ) goto abort_due_to_error;
|
||||
|
@ -97047,17 +97061,14 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
|
|||
}
|
||||
|
||||
/* Fill in pNew->pLeft and pNew->pRight. */
|
||||
zAlloc += dupedExprNodeSize(p, dupFlags);
|
||||
if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
|
||||
zAlloc += dupedExprNodeSize(p, dupFlags);
|
||||
if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){
|
||||
pNew->pLeft = p->pLeft ?
|
||||
exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0;
|
||||
pNew->pRight = p->pRight ?
|
||||
exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0;
|
||||
}
|
||||
if( pzBuffer ){
|
||||
*pzBuffer = zAlloc;
|
||||
}
|
||||
}else{
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(p, EP_Reduced|EP_TokenOnly) ){
|
||||
|
@ -97077,6 +97088,9 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
|
|||
pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
|
||||
}
|
||||
}
|
||||
if( pzBuffer ){
|
||||
*pzBuffer = zAlloc;
|
||||
}
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
@ -100628,18 +100642,15 @@ SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, i
|
|||
/*
|
||||
** This is the Expr node callback for sqlite3ExprImpliesNotNullRow().
|
||||
** If the expression node requires that the table at pWalker->iCur
|
||||
** have a non-NULL column, then set pWalker->eCode to 1 and abort.
|
||||
** have one or more non-NULL column, then set pWalker->eCode to 1 and abort.
|
||||
**
|
||||
** This routine controls an optimization. False positives (setting
|
||||
** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives
|
||||
** (never setting pWalker->eCode) is a harmless missed optimization.
|
||||
*/
|
||||
static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
/* This routine is only called for WHERE clause expressions and so it
|
||||
** cannot have any TK_AGG_COLUMN entries because those are only found
|
||||
** in HAVING clauses. We can get a TK_AGG_FUNCTION in a WHERE clause,
|
||||
** but that is an illegal construct and the query will be rejected at
|
||||
** a later stage of processing, so the TK_AGG_FUNCTION case does not
|
||||
** need to be considered here. */
|
||||
assert( pExpr->op!=TK_AGG_COLUMN );
|
||||
testcase( pExpr->op==TK_AGG_COLUMN );
|
||||
testcase( pExpr->op==TK_AGG_FUNCTION );
|
||||
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune;
|
||||
switch( pExpr->op ){
|
||||
case TK_ISNOT:
|
||||
|
@ -101298,20 +101309,6 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|||
goto exit_rename_table;
|
||||
}
|
||||
|
||||
/* If this is a virtual table, invoke the xRename() function if
|
||||
** one is defined. The xRename() callback will modify the names
|
||||
** of any resources used by the v-table implementation (including other
|
||||
** SQLite tables) that are identified by the name of the virtual table.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( pVTab ){
|
||||
int i = ++pParse->nMem;
|
||||
sqlite3VdbeLoadString(v, i, zName);
|
||||
sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB);
|
||||
sqlite3MayAbort(pParse);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* figure out how many UTF-8 characters are in zName */
|
||||
zTabName = pTab->zName;
|
||||
nTabName = sqlite3Utf8CharLen(zTabName, -1);
|
||||
|
@ -101369,6 +101366,20 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|||
, zDb, zTabName, zName, zTabName, zDb, zName);
|
||||
}
|
||||
|
||||
/* If this is a virtual table, invoke the xRename() function if
|
||||
** one is defined. The xRename() callback will modify the names
|
||||
** of any resources used by the v-table implementation (including other
|
||||
** SQLite tables) that are identified by the name of the virtual table.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( pVTab ){
|
||||
int i = ++pParse->nMem;
|
||||
sqlite3VdbeLoadString(v, i, zName);
|
||||
sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB);
|
||||
sqlite3MayAbort(pParse);
|
||||
}
|
||||
#endif
|
||||
|
||||
renameReloadSchema(pParse, iDb);
|
||||
renameTestSchema(pParse, zDb, iDb==1);
|
||||
|
||||
|
@ -102551,17 +102562,20 @@ static void renameTableFunc(
|
|||
rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
int isLegacy = (db->flags & SQLITE_LegacyAlter);
|
||||
if( sParse.pNewTable ){
|
||||
Table *pTab = sParse.pNewTable;
|
||||
|
||||
if( pTab->pSelect ){
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = &sParse;
|
||||
if( isLegacy==0 ){
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = &sParse;
|
||||
|
||||
sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
|
||||
if( sParse.nErr ) rc = sParse.rc;
|
||||
sqlite3WalkSelect(&sWalker, pTab->pSelect);
|
||||
sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
|
||||
if( sParse.nErr ) rc = sParse.rc;
|
||||
sqlite3WalkSelect(&sWalker, pTab->pSelect);
|
||||
}
|
||||
}else{
|
||||
/* Modify any FK definitions to point to the new table. */
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
|
@ -102580,7 +102594,9 @@ static void renameTableFunc(
|
|||
** "CREATE [VIRTUAL] TABLE" bit. */
|
||||
if( sqlite3_stricmp(zOld, pTab->zName)==0 ){
|
||||
sCtx.pTab = pTab;
|
||||
sqlite3WalkExprList(&sWalker, pTab->pCheck);
|
||||
if( isLegacy==0 ){
|
||||
sqlite3WalkExprList(&sWalker, pTab->pCheck);
|
||||
}
|
||||
renameTokenFind(&sParse, &sCtx, pTab->zName);
|
||||
}
|
||||
}
|
||||
|
@ -102588,7 +102604,9 @@ static void renameTableFunc(
|
|||
|
||||
else if( sParse.pNewIndex ){
|
||||
renameTokenFind(&sParse, &sCtx, sParse.pNewIndex->zName);
|
||||
sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
|
||||
if( isLegacy==0 ){
|
||||
sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
|
@ -102601,12 +102619,14 @@ static void renameTableFunc(
|
|||
renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table);
|
||||
}
|
||||
|
||||
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
||||
if( rc==SQLITE_OK ){
|
||||
renameWalkTrigger(&sWalker, pTrigger);
|
||||
for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
|
||||
if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
|
||||
renameTokenFind(&sParse, &sCtx, pStep->zTarget);
|
||||
if( isLegacy==0 ){
|
||||
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
||||
if( rc==SQLITE_OK ){
|
||||
renameWalkTrigger(&sWalker, pTrigger);
|
||||
for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
|
||||
if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
|
||||
renameTokenFind(&sParse, &sCtx, pStep->zTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102664,6 +102684,7 @@ static void renameTableTest(
|
|||
char const *zDb = (const char*)sqlite3_value_text(argv[0]);
|
||||
char const *zInput = (const char*)sqlite3_value_text(argv[1]);
|
||||
int bTemp = sqlite3_value_int(argv[4]);
|
||||
int isLegacy = (db->flags & SQLITE_LegacyAlter);
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
sqlite3_xauth xAuth = db->xAuth;
|
||||
|
@ -102676,7 +102697,7 @@ static void renameTableTest(
|
|||
Parse sParse;
|
||||
rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( sParse.pNewTable && sParse.pNewTable->pSelect ){
|
||||
if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = &sParse;
|
||||
|
@ -102685,7 +102706,9 @@ static void renameTableTest(
|
|||
}
|
||||
|
||||
else if( sParse.pNewTrigger ){
|
||||
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
||||
if( isLegacy==0 ){
|
||||
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema);
|
||||
int i2 = sqlite3FindDbName(db, zDb);
|
||||
|
@ -107335,10 +107358,6 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
|||
}
|
||||
}
|
||||
|
||||
/* The remaining transformations only apply to b-tree tables, not to
|
||||
** virtual tables */
|
||||
if( IN_DECLARE_VTAB ) return;
|
||||
|
||||
/* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
|
||||
** into BTREE_BLOBKEY.
|
||||
*/
|
||||
|
@ -119469,6 +119488,11 @@ static const PragmaName aPragmaName[] = {
|
|||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
{/* zName: */ "legacy_alter_table",
|
||||
/* ePragTyp: */ PragTyp_FLAG,
|
||||
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ SQLITE_LegacyAlter },
|
||||
{/* zName: */ "legacy_file_format",
|
||||
/* ePragTyp: */ PragTyp_FLAG,
|
||||
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
|
||||
|
@ -119722,7 +119746,7 @@ static const PragmaName aPragmaName[] = {
|
|||
/* iArg: */ SQLITE_WriteSchema },
|
||||
#endif
|
||||
};
|
||||
/* Number of pragmas: 60 on by default, 77 total. */
|
||||
/* Number of pragmas: 61 on by default, 78 total. */
|
||||
|
||||
/************** End of pragma.h **********************************************/
|
||||
/************** Continuing where we left off in pragma.c *********************/
|
||||
|
@ -125422,6 +125446,13 @@ static void generateWithRecursiveQuery(
|
|||
Expr *pLimit; /* Saved LIMIT and OFFSET */
|
||||
int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( p->pWin ){
|
||||
sqlite3ErrorMsg(pParse, "cannot use window functions in recursive queries");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Obtain authorization to do a recursive query */
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return;
|
||||
|
||||
|
@ -127171,7 +127202,7 @@ static int flattenSubquery(
|
|||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
/*
|
||||
** A structure to keep track of all of the column values that fixed to
|
||||
** A structure to keep track of all of the column values that are fixed to
|
||||
** a known value due to WHERE clause constraints of the form COLUMN=VALUE.
|
||||
*/
|
||||
typedef struct WhereConst WhereConst;
|
||||
|
@ -127183,13 +127214,28 @@ struct WhereConst {
|
|||
};
|
||||
|
||||
/*
|
||||
** Add a new entry to the pConst object
|
||||
** Add a new entry to the pConst object. Except, do not add duplicate
|
||||
** pColumn entires.
|
||||
*/
|
||||
static void constInsert(
|
||||
WhereConst *pConst,
|
||||
Expr *pColumn,
|
||||
Expr *pValue
|
||||
WhereConst *pConst, /* The WhereConst into which we are inserting */
|
||||
Expr *pColumn, /* The COLUMN part of the constraint */
|
||||
Expr *pValue /* The VALUE part of the constraint */
|
||||
){
|
||||
int i;
|
||||
assert( pColumn->op==TK_COLUMN );
|
||||
|
||||
/* 2018-10-25 ticket [cf5ed20f]
|
||||
** Make sure the same pColumn is not inserted more than once */
|
||||
for(i=0; i<pConst->nConst; i++){
|
||||
const Expr *pExpr = pConst->apExpr[i*2];
|
||||
assert( pExpr->op==TK_COLUMN );
|
||||
if( pExpr->iTable==pColumn->iTable
|
||||
&& pExpr->iColumn==pColumn->iColumn
|
||||
){
|
||||
return; /* Already present. Return without doing anything. */
|
||||
}
|
||||
}
|
||||
|
||||
pConst->nConst++;
|
||||
pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr,
|
||||
|
@ -131955,7 +132001,7 @@ static void updateVirtualTable(
|
|||
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
|
||||
sqlite3VdbeChangeP5(v, 1); /* Enable sqlite3_vtab_nochange() */
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* Enable sqlite3_vtab_nochange() */
|
||||
}
|
||||
}
|
||||
if( HasRowid(pTab) ){
|
||||
|
@ -134910,7 +134956,7 @@ static Expr *removeUnindexableInClauseTerms(
|
|||
for(i=iEq; i<pLoop->nLTerm; i++){
|
||||
if( pLoop->aLTerm[i]->pExpr==pX ){
|
||||
int iField = pLoop->aLTerm[i]->iField - 1;
|
||||
assert( pOrigRhs->a[iField].pExpr!=0 );
|
||||
if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */
|
||||
pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
|
||||
pOrigRhs->a[iField].pExpr = 0;
|
||||
assert( pOrigLhs->a[iField].pExpr!=0 );
|
||||
|
@ -138103,6 +138149,7 @@ static void exprAnalyze(
|
|||
if( pExpr->op==TK_NOTNULL
|
||||
&& pExpr->pLeft->op==TK_COLUMN
|
||||
&& pExpr->pLeft->iColumn>=0
|
||||
&& !ExprHasProperty(pExpr, EP_FromJoin)
|
||||
&& OptimizationEnabled(db, SQLITE_Stat34)
|
||||
){
|
||||
Expr *pNewExpr;
|
||||
|
@ -154763,6 +154810,7 @@ static int openDatabase(
|
|||
db->nDb = 2;
|
||||
db->magic = SQLITE_MAGIC_BUSY;
|
||||
db->aDb = db->aDbStatic;
|
||||
db->lookaside.bDisable = 1;
|
||||
|
||||
assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
|
||||
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
|
||||
|
@ -159141,7 +159189,7 @@ static int fts3ScanInteriorNode(
|
|||
const char *zCsr = zNode; /* Cursor to iterate through node */
|
||||
const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
|
||||
char *zBuffer = 0; /* Buffer to load terms into */
|
||||
int nAlloc = 0; /* Size of allocated buffer */
|
||||
i64 nAlloc = 0; /* Size of allocated buffer */
|
||||
int isFirstTerm = 1; /* True when processing first term on page */
|
||||
sqlite3_int64 iChild; /* Block id of child node to descend to */
|
||||
|
||||
|
@ -159179,14 +159227,14 @@ static int fts3ScanInteriorNode(
|
|||
zCsr += fts3GetVarint32(zCsr, &nSuffix);
|
||||
|
||||
assert( nPrefix>=0 && nSuffix>=0 );
|
||||
if( &zCsr[nSuffix]>zEnd ){
|
||||
if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
goto finish_scan;
|
||||
}
|
||||
if( nPrefix+nSuffix>nAlloc ){
|
||||
if( (i64)nPrefix+nSuffix>nAlloc ){
|
||||
char *zNew;
|
||||
nAlloc = (nPrefix+nSuffix) * 2;
|
||||
zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
|
||||
nAlloc = ((i64)nPrefix+nSuffix) * 2;
|
||||
zNew = (char *)sqlite3_realloc64(zBuffer, nAlloc);
|
||||
if( !zNew ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto finish_scan;
|
||||
|
@ -168768,15 +168816,19 @@ static int fts3SegReaderNext(
|
|||
** safe (no risk of overread) even if the node data is corrupted. */
|
||||
pNext += fts3GetVarint32(pNext, &nPrefix);
|
||||
pNext += fts3GetVarint32(pNext, &nSuffix);
|
||||
if( nPrefix<0 || nSuffix<=0
|
||||
|| &pNext[nSuffix]>&pReader->aNode[pReader->nNode]
|
||||
if( nSuffix<=0
|
||||
|| (&pReader->aNode[pReader->nNode] - pNext)<nSuffix
|
||||
|| nPrefix>pReader->nTermAlloc
|
||||
){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
if( nPrefix+nSuffix>pReader->nTermAlloc ){
|
||||
int nNew = (nPrefix+nSuffix)*2;
|
||||
char *zNew = sqlite3_realloc(pReader->zTerm, nNew);
|
||||
/* Both nPrefix and nSuffix were read by fts3GetVarint32() and so are
|
||||
** between 0 and 0x7FFFFFFF. But the sum of the two may cause integer
|
||||
** overflow - hence the (i64) casts. */
|
||||
if( (i64)nPrefix+nSuffix>(i64)pReader->nTermAlloc ){
|
||||
i64 nNew = ((i64)nPrefix+nSuffix)*2;
|
||||
char *zNew = sqlite3_realloc64(pReader->zTerm, nNew);
|
||||
if( !zNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
@ -168798,7 +168850,7 @@ static int fts3SegReaderNext(
|
|||
** b-tree node. And that the final byte of the doclist is 0x00. If either
|
||||
** of these statements is untrue, then the data structure is corrupt.
|
||||
*/
|
||||
if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode]
|
||||
if( (&pReader->aNode[pReader->nNode] - pReader->aDoclist)<pReader->nDoclist
|
||||
|| (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
|
||||
){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
|
@ -171124,6 +171176,9 @@ static int nodeReaderNext(NodeReader *p){
|
|||
}
|
||||
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);
|
||||
|
||||
if( nPrefix>p->iOff || nSuffix>p->nNode-p->iOff ){
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
|
||||
|
@ -171131,6 +171186,9 @@ static int nodeReaderNext(NodeReader *p){
|
|||
p->iOff += nSuffix;
|
||||
if( p->iChild==0 ){
|
||||
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
|
||||
if( (p->nNode-p->iOff)<p->nDoclist ){
|
||||
return SQLITE_CORRUPT_VTAB;
|
||||
}
|
||||
p->aDoclist = &p->aNode[p->iOff];
|
||||
p->iOff += p->nDoclist;
|
||||
}
|
||||
|
@ -171138,7 +171196,6 @@ static int nodeReaderNext(NodeReader *p){
|
|||
}
|
||||
|
||||
assert( p->iOff<=p->nNode );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -214424,7 +214481,7 @@ static void fts5SourceIdFunc(
|
|||
){
|
||||
assert( nArg==0 );
|
||||
UNUSED_PARAM2(nArg, apUnused);
|
||||
sqlite3_result_text(pCtx, "fts5: 2018-09-18 20:20:44 2ac9003de44da7dafa3fbb1915ac5725a9275c86bf2f3b7aa19321bf1460b386", -1, SQLITE_TRANSIENT);
|
||||
sqlite3_result_text(pCtx, "fts5: 2018-11-05 20:37:38 89e099fbe5e13c33e683bef07361231ca525b88f7907be7092058007b75036f2", -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
static int fts5Init(sqlite3 *db){
|
||||
|
@ -219134,9 +219191,9 @@ SQLITE_API int sqlite3_stmt_init(
|
|||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
|
||||
|
||||
/************** End of stmt.c ************************************************/
|
||||
#if __LINE__!=219137
|
||||
#if __LINE__!=219194
|
||||
#undef SQLITE_SOURCE_ID
|
||||
#define SQLITE_SOURCE_ID "2018-09-18 20:20:44 2ac9003de44da7dafa3fbb1915ac5725a9275c86bf2f3b7aa19321bf1460alt2"
|
||||
#define SQLITE_SOURCE_ID "2018-11-05 20:37:38 89e099fbe5e13c33e683bef07361231ca525b88f7907be7092058007b750alt2"
|
||||
#endif
|
||||
/* Return the source-id for this library */
|
||||
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
|
||||
|
|
|
@ -123,9 +123,9 @@ extern "C" {
|
|||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.25.1"
|
||||
#define SQLITE_VERSION_NUMBER 3025001
|
||||
#define SQLITE_SOURCE_ID "2018-09-18 20:20:44 2ac9003de44da7dafa3fbb1915ac5725a9275c86bf2f3b7aa19321bf1460b386"
|
||||
#define SQLITE_VERSION "3.25.3"
|
||||
#define SQLITE_VERSION_NUMBER 3025003
|
||||
#define SQLITE_SOURCE_ID "2018-11-05 20:37:38 89e099fbe5e13c33e683bef07361231ca525b88f7907be7092058007b75036f2"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
|
|
|
@ -214,7 +214,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
|
|||
toolbox.hostType == Toolbox.HostType.WINDOW) {
|
||||
toolbox.raise();
|
||||
} else {
|
||||
gDevTools.closeToolbox(target);
|
||||
toolbox.destroy();
|
||||
}
|
||||
gDevTools.emit("select-tool-command", toolId);
|
||||
} else {
|
||||
|
|
|
@ -26,7 +26,7 @@ add_task(async function() {
|
|||
|
||||
is(store.getState().requests.requests.size, 0, "No network requests appear in the network panel");
|
||||
|
||||
await gDevTools.closeToolbox(target);
|
||||
await toolbox.destroy();
|
||||
tab = target = toolbox = panel = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
|
@ -32,7 +32,7 @@ add_task(async function() {
|
|||
|
||||
let toolbox = await gDevTools.showToolbox(target, testToolDefinition.id);
|
||||
is(toolbox.currentToolId, "testTool", "test-tool was selected");
|
||||
await gDevTools.closeToolbox(target);
|
||||
await toolbox.destroy();
|
||||
|
||||
// Make the previously selected tool unavailable.
|
||||
testToolDefinition.isTargetSupported = () => false;
|
||||
|
@ -41,7 +41,7 @@ add_task(async function() {
|
|||
toolbox = await gDevTools.showToolbox(target);
|
||||
is(toolbox.currentToolId, "webconsole", "web console was selected");
|
||||
|
||||
await gDevTools.closeToolbox(target);
|
||||
await toolbox.destroy();
|
||||
gDevTools.unregisterTool(testToolDefinition.id);
|
||||
tab = toolbox = target = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
|
|
|
@ -20,41 +20,33 @@ class FlexItemSizingProperties extends PureComponent {
|
|||
}
|
||||
|
||||
/**
|
||||
* Rounds some dimension in pixels and returns a string to be displayed to the user.
|
||||
* The string will end with 'px'. If the number is 0, the string "0" is returned.
|
||||
* Rounds some size in pixels and render it.
|
||||
* The rendered value will end with 'px' (unless the dimension is 0 in which case the
|
||||
* unit will be omitted)
|
||||
*
|
||||
* @param {Number} value
|
||||
* The number to be rounded
|
||||
* @return {String}
|
||||
* Representation of the rounded number
|
||||
* @param {Boolean} prependPlusSign
|
||||
* If set to true, the + sign will be printed before a positive value
|
||||
* @return {Object}
|
||||
* The React component representing this rounded size
|
||||
*/
|
||||
getRoundedDimension(value) {
|
||||
renderSize(value, prependPlusSign) {
|
||||
if (value == 0) {
|
||||
return "0";
|
||||
}
|
||||
return (Math.round(value * 100) / 100) + "px";
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the flexibility value into a meaningful value for the UI.
|
||||
* If the item grew, then prepend a + sign, if it shrank, prepend a - sign.
|
||||
* If it didn't flex, return "0".
|
||||
*
|
||||
* @param {Boolean} grew
|
||||
* Whether the item grew or not
|
||||
* @param {Number} value
|
||||
* The amount of pixels the item flexed
|
||||
* @return {String}
|
||||
* Representation of the flexibility value
|
||||
*/
|
||||
getFlexibilityValueString(grew, mainDeltaSize) {
|
||||
const value = this.getRoundedDimension(mainDeltaSize);
|
||||
|
||||
if (grew) {
|
||||
return "+" + value;
|
||||
return dom.span({ className: "value" }, "0");
|
||||
}
|
||||
|
||||
return value;
|
||||
value = (Math.round(value * 100) / 100);
|
||||
if (prependPlusSign && value > 0) {
|
||||
value = "+" + value;
|
||||
}
|
||||
|
||||
return (
|
||||
dom.span({ className: "value" },
|
||||
value,
|
||||
dom.span({ className: "unit" }, "px")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,14 +62,7 @@ class FlexItemSizingProperties extends PureComponent {
|
|||
* The React component representing this CSS property
|
||||
*/
|
||||
renderCssProperty(name, value, isDefaultValue) {
|
||||
return (
|
||||
dom.span({ className: "css-property-link" },
|
||||
dom.span({ className: "theme-fg-color5" }, name),
|
||||
": ",
|
||||
dom.span({ className: "theme-fg-color1" }, value),
|
||||
";"
|
||||
)
|
||||
);
|
||||
return dom.span({ className: "css-property-link" }, `(${name}: ${value})`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,12 +105,10 @@ class FlexItemSizingProperties extends PureComponent {
|
|||
return (
|
||||
dom.li({ className: className + (property ? "" : " no-property") },
|
||||
dom.span({ className: "name" },
|
||||
getStr("flexbox.itemSizing.baseSizeSectionHeader")
|
||||
getStr("flexbox.itemSizing.baseSizeSectionHeader"),
|
||||
property
|
||||
),
|
||||
dom.span({ className: "value theme-fg-color1" },
|
||||
this.getRoundedDimension(mainBaseSize)
|
||||
),
|
||||
property,
|
||||
this.renderSize(mainBaseSize),
|
||||
reason
|
||||
)
|
||||
);
|
||||
|
@ -216,12 +199,10 @@ class FlexItemSizingProperties extends PureComponent {
|
|||
return (
|
||||
dom.li({ className: className + (property ? "" : " no-property") },
|
||||
dom.span({ className: "name" },
|
||||
getStr("flexbox.itemSizing.flexibilitySectionHeader")
|
||||
getStr("flexbox.itemSizing.flexibilitySectionHeader"),
|
||||
property
|
||||
),
|
||||
dom.span({ className: "value theme-fg-color1" },
|
||||
this.getFlexibilityValueString(grew, mainDeltaSize)
|
||||
),
|
||||
property,
|
||||
this.renderSize(mainDeltaSize, true),
|
||||
this.renderReasons(reasons)
|
||||
)
|
||||
);
|
||||
|
@ -239,12 +220,10 @@ class FlexItemSizingProperties extends PureComponent {
|
|||
return (
|
||||
dom.li({ className: "section min" },
|
||||
dom.span({ className: "name" },
|
||||
getStr("flexbox.itemSizing.minSizeSectionHeader")
|
||||
getStr("flexbox.itemSizing.minSizeSectionHeader"),
|
||||
this.renderCssProperty(`min-${dimension}`, minDimensionValue)
|
||||
),
|
||||
dom.span({ className: "value theme-fg-color1" },
|
||||
this.getRoundedDimension(mainMinSize)
|
||||
),
|
||||
this.renderCssProperty(`min-${dimension}`, minDimensionValue)
|
||||
this.renderSize(mainMinSize)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -259,12 +238,10 @@ class FlexItemSizingProperties extends PureComponent {
|
|||
return (
|
||||
dom.li({ className: "section max" },
|
||||
dom.span({ className: "name" },
|
||||
getStr("flexbox.itemSizing.maxSizeSectionHeader")
|
||||
getStr("flexbox.itemSizing.maxSizeSectionHeader"),
|
||||
this.renderCssProperty(`max-${dimension}`, maxDimensionValue)
|
||||
),
|
||||
dom.span({ className: "value theme-fg-color1" },
|
||||
this.getRoundedDimension(mainMaxSize)
|
||||
),
|
||||
this.renderCssProperty(`max-${dimension}`, maxDimensionValue)
|
||||
this.renderSize(mainMaxSize)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -275,9 +252,7 @@ class FlexItemSizingProperties extends PureComponent {
|
|||
dom.span({ className: "name" },
|
||||
getStr("flexbox.itemSizing.finalSizeSectionHeader")
|
||||
),
|
||||
dom.span({ className: "value theme-fg-color1" },
|
||||
this.getRoundedDimension(mainFinalSize)
|
||||
)
|
||||
this.renderSize(mainFinalSize)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ support-files =
|
|||
!/devtools/client/inspector/test/head.js
|
||||
!/devtools/client/inspector/test/shared-head.js
|
||||
!/devtools/client/shared/test/shared-head.js
|
||||
!/devtools/client/shared/test/shared-redux-head.js
|
||||
!/devtools/client/shared/test/telemetry-test-helpers.js
|
||||
!/devtools/client/shared/test/test-actor.js
|
||||
!/devtools/client/shared/test/test-actor-registry.js
|
||||
|
|
|
@ -25,8 +25,9 @@ add_task(async function() {
|
|||
info("Check that the base, flexibility and final sizes are displayed");
|
||||
const allSections = [...flexSizingContainer.querySelectorAll(".section .name")];
|
||||
const allSectionTitles = allSections.map(el => el.textContent);
|
||||
const expectedTitles = ["Base Size", "Flexibility", "Final Size"];
|
||||
|
||||
ok(expectedTitles.every(title => allSectionTitles.includes(title)),
|
||||
"The 3 main sizing sections where found");
|
||||
["Base Size", "Flexibility", "Final Size"].forEach((expectedTitle, i) => {
|
||||
ok(allSectionTitles[i].includes(expectedTitle),
|
||||
`Sizing section #${i + 1} (${expectedTitle}) was found`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -20,10 +20,10 @@ async function checkFlexItemDimension(inspector, doc, selector, expectedDimensio
|
|||
info("Check that the minimum size section shows the correct dimension.");
|
||||
const [sectionMinRowItem] = [...flexItemSizingContainer.querySelectorAll(
|
||||
".section.min")];
|
||||
const minDimension = sectionMinRowItem.querySelector(".theme-fg-color5");
|
||||
const minDimension = sectionMinRowItem.querySelector(".css-property-link");
|
||||
|
||||
is(minDimension.textContent, expectedDimension,
|
||||
"The flex item sizing has the correct dimension value.");
|
||||
ok(minDimension.textContent.includes(expectedDimension),
|
||||
"The flex item sizing has the correct dimension value.");
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
|
|
|
@ -35,7 +35,8 @@ add_task(async function() {
|
|||
|
||||
is(sections.length, expectedSections.length, "Correct number of sections found");
|
||||
expectedSections.forEach((expectedSection, i) => {
|
||||
is(sections[i], expectedSection, `The ${expectedSection} section was found`);
|
||||
ok(sections[i].includes(expectedSection),
|
||||
`The ${expectedSection} section was found`);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -58,7 +58,7 @@ add_task(async function() {
|
|||
await assertMarkupView(inspector);
|
||||
|
||||
info("Close DevTools before testing Inspect Element");
|
||||
await gDevTools.closeToolbox(inspector.target);
|
||||
await toolbox.destroy();
|
||||
|
||||
info("Waiting for element picker to become active.");
|
||||
const newTestActor = await getTestActorWithoutToolbox(tab);
|
||||
|
|
|
@ -35,7 +35,7 @@ add_task(async function() {
|
|||
ok(splitter.classList.contains("horz"), "Splitter is in horizontal mode");
|
||||
|
||||
info("Close the inspector");
|
||||
await gDevTools.closeToolbox(toolbox.target);
|
||||
await toolbox.destroy();
|
||||
|
||||
info("Reopen inspector");
|
||||
({ inspector, toolbox } = await openInspector("window"));
|
||||
|
|
|
@ -26,8 +26,7 @@ async function runTests([win, sp]) {
|
|||
const target = await TargetFactory.forTab(gBrowser.selectedTab);
|
||||
const toolbox = await gDevTools.showToolbox(target, "webconsole");
|
||||
ok(toolbox, "Toolbox was opened.");
|
||||
const closed = await gDevTools.closeToolbox(target);
|
||||
is(closed, true, "Toolbox was closed.");
|
||||
await toolbox.destroy();
|
||||
|
||||
// Now see if using the scratcphad works as expected.
|
||||
sp.setText(source);
|
||||
|
|
|
@ -28,7 +28,7 @@ add_task(async function testNormalExecution() {
|
|||
|
||||
terminateWorkerInTab(tab, WORKER_URL);
|
||||
await waitForWorkerClose(workerTargetFront);
|
||||
await gDevTools.closeToolbox(TargetFactory.forWorker(workerTargetFront));
|
||||
await toolbox.destroy();
|
||||
await close(client);
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
|
|
@ -56,7 +56,7 @@ add_task(async function testWhilePaused() {
|
|||
|
||||
terminateWorkerInTab(tab, WORKER_URL);
|
||||
await waitForWorkerClose(workerTargetFront);
|
||||
await gDevTools.closeToolbox(TargetFactory.forWorker(workerTargetFront));
|
||||
await toolbox.destroy();
|
||||
await close(client);
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
|
|
@ -47,7 +47,7 @@ add_task(async function testPausedByConsole() {
|
|||
|
||||
terminateWorkerInTab(tab, WORKER_URL);
|
||||
await waitForWorkerClose(workerTargetFront);
|
||||
await gDevTools.closeToolbox(TargetFactory.forWorker(workerTargetFront));
|
||||
await toolbox.destroy();
|
||||
await close(client);
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
|
|
@ -43,7 +43,7 @@ add_task(async function testPausedByConsole() {
|
|||
|
||||
terminateWorkerInTab(tab, WORKER_URL);
|
||||
await waitForWorkerClose(workerTargetFront);
|
||||
await gDevTools.closeToolbox(TargetFactory.forWorker(workerTargetFront));
|
||||
await toolbox.destroy();
|
||||
await close(client);
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@ add_task(async function() {
|
|||
info("testing the eyedropper button");
|
||||
await testButton(toolbox);
|
||||
|
||||
await gDevTools.closeToolbox(target);
|
||||
await toolbox.destroy();
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ add_task(async function() {
|
|||
info("testing the paintflashing button");
|
||||
await testButton(toolbox);
|
||||
|
||||
await gDevTools.closeToolbox(target);
|
||||
await toolbox.destroy();
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ add_task(async function() {
|
|||
info("testing the responsivedesign button");
|
||||
await testButton(toolbox);
|
||||
|
||||
await gDevTools.closeToolbox(target);
|
||||
await toolbox.destroy();
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ add_task(async function() {
|
|||
|
||||
checkResults();
|
||||
|
||||
await gDevTools.closeToolbox(target);
|
||||
await toolbox.destroy();
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ add_task(async function() {
|
|||
checkResults();
|
||||
checkEventTelemetry();
|
||||
|
||||
await gDevTools.closeToolbox(target);
|
||||
await toolbox.destroy();
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
|
|
|
@ -132,13 +132,13 @@ async function openAndCloseToolbox(nbOfTimes, usageTime, toolId) {
|
|||
for (let i = 0; i < nbOfTimes; i++) {
|
||||
info("Opening toolbox " + (i + 1));
|
||||
const target = await TargetFactory.forTab(gBrowser.selectedTab);
|
||||
await gDevTools.showToolbox(target, toolId);
|
||||
const toolbox = await gDevTools.showToolbox(target, toolId);
|
||||
|
||||
// We use a timeout to check the toolbox's active time
|
||||
await new Promise(resolve => setTimeout(resolve, usageTime));
|
||||
|
||||
info("Closing toolbox " + (i + 1));
|
||||
await gDevTools.closeToolbox(target);
|
||||
await toolbox.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -136,6 +136,8 @@ function Editor(config) {
|
|||
themeSwitching: true,
|
||||
autocomplete: false,
|
||||
autocompleteOpts: {},
|
||||
// Set to true to prevent the search addon to be activated.
|
||||
disableSearchAddon: false,
|
||||
};
|
||||
|
||||
// Additional shortcuts.
|
||||
|
@ -438,7 +440,9 @@ Editor.prototype = {
|
|||
return L10N.getStr(name);
|
||||
});
|
||||
|
||||
this._initShortcuts(win);
|
||||
if (!this.config.disableSearchAddon) {
|
||||
this._initSearchShortcuts(win);
|
||||
}
|
||||
|
||||
editors.set(this, cm);
|
||||
|
||||
|
@ -1398,11 +1402,11 @@ Editor.prototype = {
|
|||
/**
|
||||
* Register all key shortcuts.
|
||||
*/
|
||||
_initShortcuts: function(win) {
|
||||
_initSearchShortcuts: function(win) {
|
||||
const shortcuts = new KeyShortcuts({
|
||||
window: win,
|
||||
});
|
||||
this._onShortcut = this._onShortcut.bind(this);
|
||||
this._onSearchShortcut = this._onSearchShortcut.bind(this);
|
||||
const keys = [
|
||||
"find.key",
|
||||
"findNext.key",
|
||||
|
@ -1417,13 +1421,13 @@ Editor.prototype = {
|
|||
// Process generic keys:
|
||||
keys.forEach(name => {
|
||||
const key = L10N.getStr(name);
|
||||
shortcuts.on(key, event => this._onShortcut(name, event));
|
||||
shortcuts.on(key, event => this._onSearchShortcut(name, event));
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Key shortcut listener.
|
||||
*/
|
||||
_onShortcut: function(name, event) {
|
||||
_onSearchShortcut: function(name, event) {
|
||||
if (!this._isInputOrTextarea(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -389,30 +389,22 @@
|
|||
*/
|
||||
|
||||
.flex-item-sizing {
|
||||
margin: 20px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.flex-item-sizing .section {
|
||||
--padding: 10px;
|
||||
margin-block-start: var(--padding);
|
||||
padding: var(--padding) 0 0 0;
|
||||
padding: var(--padding);
|
||||
border-block-start: 1px solid var(--theme-splitter-color);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr max-content;
|
||||
grid-column-gap: var(--padding);
|
||||
}
|
||||
|
||||
/* If the outline isn't displayed before the sizing information, then no need for a first
|
||||
top border or padding */
|
||||
:not(.flex-outline-container) + .flex-item-sizing > .section:first-child {
|
||||
border: 0;
|
||||
padding-block-start: 0;
|
||||
}
|
||||
|
||||
.flex-item-sizing .section:first-child {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.flex-item-sizing .name {
|
||||
|
@ -425,9 +417,14 @@
|
|||
font-weight: 600;
|
||||
}
|
||||
|
||||
.flex-item-sizing .value .unit {
|
||||
color: var(--theme-comment);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.flex-item-sizing .css-property-link {
|
||||
grid-column: 2;
|
||||
text-align: end;
|
||||
font-weight: normal;
|
||||
margin-inline-start: .5em;
|
||||
}
|
||||
|
||||
.flex-item-sizing .reasons,
|
||||
|
|
|
@ -200,6 +200,7 @@ class JSTerm extends Component {
|
|||
styleActiveLine: false,
|
||||
tabIndex: "0",
|
||||
viewportMargin: Infinity,
|
||||
disableSearchAddon: true,
|
||||
extraKeys: {
|
||||
"Enter": () => {
|
||||
// No need to handle shift + Enter as it's natively handled by CodeMirror.
|
||||
|
|
|
@ -19,14 +19,14 @@ const TEST_URI =
|
|||
add_task(async function() {
|
||||
// Run in legacy JsTerm.
|
||||
await pushPref("devtools.webconsole.jsterm.codeMirror", false);
|
||||
await testHistory();
|
||||
await performTests();
|
||||
|
||||
// And then in codeMirror JsTerm.
|
||||
await pushPref("devtools.webconsole.jsterm.codeMirror", true);
|
||||
await testHistory();
|
||||
await performTests();
|
||||
});
|
||||
|
||||
async function testHistory() {
|
||||
async function performTests() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
info("Web Console opened");
|
||||
const outputScroller = hud.ui.outputScroller;
|
||||
|
@ -70,6 +70,11 @@ async function testHistory() {
|
|||
info("try ctrl-f to focus filter");
|
||||
synthesizeKeyShortcut(WCUL10n.getStr("webconsole.find.key"));
|
||||
ok(!isJstermFocused(hud.jsterm), "jsterm input is not focused");
|
||||
ok(hasFocus(hud.ui.filterBox), "filter input is focused");
|
||||
|
||||
info("try ctrl-f when filter is already focused");
|
||||
synthesizeKeyShortcut(WCUL10n.getStr("webconsole.find.key"));
|
||||
ok(!isJstermFocused(hud.jsterm), "jsterm input is not focused");
|
||||
is(hud.ui.filterBox, outputScroller.ownerDocument.activeElement,
|
||||
"filter input is focused");
|
||||
}
|
||||
|
|
|
@ -545,10 +545,14 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
if (steppingType == "finish") {
|
||||
const parentFrame = thread._getNextStepFrame(this);
|
||||
if (parentFrame && parentFrame.script) {
|
||||
const { onStep } = thread._makeSteppingHooks(
|
||||
const { onStep, onPop } = thread._makeSteppingHooks(
|
||||
originalLocation, "next", false, completion
|
||||
);
|
||||
parentFrame.onStep = onStep;
|
||||
// We need the onPop alongside the onStep because it is possible that
|
||||
// the parent frame won't have any steppable offsets, and we want to
|
||||
// make sure that we always pause in the parent _somewhere_.
|
||||
parentFrame.onPop = onPop;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Check that step out stops at the end of the parent if it fails to stop
|
||||
* anywhere else. Bug 1504358.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gCallback;
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
run_test_with_server(DebuggerServer, function() {
|
||||
run_test_with_server(WorkerDebuggerServer, do_test_finished);
|
||||
});
|
||||
}
|
||||
|
||||
function run_test_with_server(server, callback) {
|
||||
gCallback = callback;
|
||||
initTestDebuggerServer(server);
|
||||
gDebuggee = addTestGlobal("test-stepping", server);
|
||||
gClient = new DebuggerClient(server.connectPipe());
|
||||
gClient.connect(testStepOutWithBreakpoint);
|
||||
}
|
||||
|
||||
async function testStepOutWithBreakpoint() {
|
||||
const [attachResponse,, threadClient] = await attachTestTabAndResume(gClient,
|
||||
"test-stepping");
|
||||
ok(!attachResponse.error, "Should not get an error attaching");
|
||||
|
||||
dumpn("Evaluating test code and waiting for first debugger statement");
|
||||
const dbgStmt = await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
|
||||
equal(dbgStmt.frame.where.line, 2, "Should be at debugger statement on line 2");
|
||||
|
||||
dumpn("Step out of inner and into outer");
|
||||
const step2 = await stepOut(gClient, threadClient);
|
||||
// The bug was that we'd step right past the end of the function and never pause.
|
||||
equal(step2.frame.where.line, 2);
|
||||
equal(step2.why.frameFinished.return, 42);
|
||||
|
||||
finishClient(gClient, gCallback);
|
||||
}
|
||||
|
||||
function evaluateTestCode() {
|
||||
// By placing the inner and outer on the same line, this triggers the server's
|
||||
// logic to skip steps for these functions, meaning that onPop is the only
|
||||
// thing that will cause it to pop.
|
||||
Cu.evalInSandbox(
|
||||
`
|
||||
function outer(){ inner(); return 42; } function inner(){ debugger; }
|
||||
outer();
|
||||
`,
|
||||
gDebuggee,
|
||||
"1.8",
|
||||
"test_stepping-09-test-code.js",
|
||||
1
|
||||
);
|
||||
}
|
|
@ -196,6 +196,7 @@ reason = bug 1104838
|
|||
[test_stepping-06.js]
|
||||
[test_stepping-07.js]
|
||||
[test_stepping-08.js]
|
||||
[test_stepping-09.js]
|
||||
[test_stepping-with-pause-points.js]
|
||||
[test_stepping-with-skip-breakpoints.js]
|
||||
[test_framebindings-01.js]
|
||||
|
|
|
@ -424,6 +424,10 @@ nsDocShell::~nsDocShell()
|
|||
// Avoid notifying observers while we're in the dtor.
|
||||
mIsBeingDestroyed = true;
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
profiler_unregister_pages(mHistoryID);
|
||||
#endif
|
||||
|
||||
Destroy();
|
||||
|
||||
if (mSessionHistory) {
|
||||
|
@ -2526,8 +2530,6 @@ nsDocShell::SetCustomUserAgent(const nsAString& aCustomUserAgent)
|
|||
NS_IMETHODIMP
|
||||
nsDocShell::GetTouchEventsOverride(uint32_t* aTouchEventsOverride)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aTouchEventsOverride);
|
||||
|
||||
*aTouchEventsOverride = mTouchEventsOverride;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -11360,6 +11362,21 @@ nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
// We register the page load only if the load updates the history and it's not
|
||||
// a refresh. This also registers the iframes in shift-reload case, but it's
|
||||
// reasonable to register since we are updating the historyId in that case.
|
||||
if (updateSHistory) {
|
||||
uint32_t id = 0;
|
||||
nsAutoCString spec;
|
||||
if (mLSHE) {
|
||||
mLSHE->GetID(&id);
|
||||
}
|
||||
aURI->GetSpec(spec);
|
||||
profiler_register_page(mHistoryID, id, spec, IsFrame());
|
||||
}
|
||||
#endif
|
||||
|
||||
// If this is a POST request, we do not want to include this in global
|
||||
// history.
|
||||
if (updateGHistory && aAddToGlobalHistory && !ChannelIsPost(aChannel)) {
|
||||
|
@ -11670,6 +11687,12 @@ nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
|
|||
// we'll just set mOSHE here.
|
||||
mOSHE = newSHEntry;
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
uint32_t id = 0;
|
||||
GetOSHEId(&id);
|
||||
profiler_register_page(mHistoryID, id, NS_ConvertUTF16toUTF8(aURL), IsFrame());
|
||||
#endif
|
||||
|
||||
} else {
|
||||
newSHEntry = mOSHE;
|
||||
newSHEntry->SetURI(newURI);
|
||||
|
@ -13759,6 +13782,17 @@ nsDocShell::SetOriginAttributes(JS::Handle<JS::Value> aOriginAttributes,
|
|||
return SetOriginAttributes(attrs);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetOSHEId(uint32_t* aSHEntryId)
|
||||
{
|
||||
if (mOSHE) {
|
||||
mOSHE->GetID(aSHEntryId);
|
||||
return NS_OK;
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
|
||||
{
|
||||
|
@ -14039,7 +14073,6 @@ nsIDocShell::SetHTMLEditor(HTMLEditor* aHTMLEditor)
|
|||
NS_IMETHODIMP
|
||||
nsDocShell::GetDisplayMode(uint32_t* aDisplayMode)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDisplayMode);
|
||||
*aDisplayMode = mDisplayMode;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -1091,6 +1091,8 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||
in string asyncCause);
|
||||
[noscript,notxpcom,nostdcall] void notifyJSRunToCompletionStop();
|
||||
|
||||
[noscript] void GetOSHEId(out uint32_t aSHEntryId);
|
||||
|
||||
/**
|
||||
* This attribute determines whether a document which is not about:blank has
|
||||
* already be loaded by this docShell.
|
||||
|
@ -1136,7 +1138,7 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||
* This allows chrome to override the default choice of whether touch events
|
||||
* are available on a specific docshell. Possible values are listed below.
|
||||
*/
|
||||
attribute unsigned long touchEventsOverride;
|
||||
[infallible] attribute unsigned long touchEventsOverride;
|
||||
/**
|
||||
* Override platform/pref default behaviour and force-disable touch events.
|
||||
*/
|
||||
|
@ -1252,7 +1254,7 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||
* Display mode for this docshell. Defaults to DISPLAY_MODE_BROWSER.
|
||||
* Media queries only look at the value in the top-most docshell.
|
||||
*/
|
||||
attribute unsigned long displayMode;
|
||||
[infallible] attribute unsigned long displayMode;
|
||||
|
||||
/**
|
||||
* The message manager for this docshell. This does not throw, but
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/ComputedStyleInlines.h"
|
||||
#include "mozilla/EffectSet.h"
|
||||
#include "mozilla/LayerAnimationInfo.h"
|
||||
#include "mozilla/RestyleManager.h"
|
||||
#include "mozilla/ServoBindings.h" // Servo_GetProperties_Overriding_Animation
|
||||
#include "mozilla/ServoStyleSet.h"
|
||||
|
@ -609,7 +608,9 @@ EffectCompositor::GetOverriddenProperties(EffectSet& aEffectSet,
|
|||
return result;
|
||||
}
|
||||
|
||||
AutoTArray<nsCSSPropertyID, LayerAnimationInfo::kRecords> propertiesToTrack;
|
||||
static constexpr size_t compositorAnimatableCount =
|
||||
nsCSSPropertyIDSet::CompositorAnimatableCount();
|
||||
AutoTArray<nsCSSPropertyID, compositorAnimatableCount> propertiesToTrack;
|
||||
{
|
||||
nsCSSPropertyIDSet propertiesToTrackAsSet;
|
||||
for (KeyframeEffect* effect : aEffectSet) {
|
||||
|
@ -623,7 +624,7 @@ EffectCompositor::GetOverriddenProperties(EffectSet& aEffectSet,
|
|||
}
|
||||
// Skip iterating over the rest of the effects if we've already
|
||||
// found all the compositor-animatable properties.
|
||||
if (propertiesToTrack.Length() == LayerAnimationInfo::kRecords) {
|
||||
if (propertiesToTrack.Length() == compositorAnimatableCount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -666,31 +667,17 @@ EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet,
|
|||
nsCSSPropertyIDSet overriddenProperties =
|
||||
GetOverriddenProperties(aEffectSet, aElement, aPseudoType);
|
||||
|
||||
// Returns a bitset the represents which properties from
|
||||
// LayerAnimationInfo::sRecords are present in |aPropertySet|.
|
||||
auto compositorPropertiesInSet =
|
||||
[](nsCSSPropertyIDSet& aPropertySet) ->
|
||||
std::bitset<LayerAnimationInfo::kRecords> {
|
||||
std::bitset<LayerAnimationInfo::kRecords> result;
|
||||
for (size_t i = 0; i < LayerAnimationInfo::kRecords; i++) {
|
||||
if (aPropertySet.HasProperty(
|
||||
LayerAnimationInfo::sRecords[i].mProperty)) {
|
||||
result.set(i);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
nsCSSPropertyIDSet& propertiesWithImportantRules =
|
||||
aEffectSet.PropertiesWithImportantRules();
|
||||
nsCSSPropertyIDSet& propertiesForAnimationsLevel =
|
||||
aEffectSet.PropertiesForAnimationsLevel();
|
||||
|
||||
static constexpr nsCSSPropertyIDSet compositorAnimatables =
|
||||
nsCSSPropertyIDSet::CompositorAnimatables();
|
||||
// Record which compositor-animatable properties were originally set so we can
|
||||
// compare for changes later.
|
||||
std::bitset<LayerAnimationInfo::kRecords>
|
||||
prevCompositorPropertiesWithImportantRules =
|
||||
compositorPropertiesInSet(propertiesWithImportantRules);
|
||||
nsCSSPropertyIDSet prevCompositorPropertiesWithImportantRules =
|
||||
propertiesWithImportantRules.Intersect(compositorAnimatables);
|
||||
|
||||
nsCSSPropertyIDSet prevPropertiesForAnimationsLevel =
|
||||
propertiesForAnimationsLevel;
|
||||
|
@ -732,8 +719,8 @@ EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet,
|
|||
// released from being overridden by !important rules, we need to update
|
||||
// layers for animations level because it's a trigger to send animations to
|
||||
// the compositor or pull animations back from the compositor.
|
||||
if (prevCompositorPropertiesWithImportantRules !=
|
||||
compositorPropertiesInSet(propertiesWithImportantRules)) {
|
||||
if (!prevCompositorPropertiesWithImportantRules.Equals(
|
||||
propertiesWithImportantRules.Intersect(compositorAnimatables))) {
|
||||
presContext->EffectCompositor()->
|
||||
RequestRestyle(aElement, aPseudoType,
|
||||
EffectCompositor::RestyleType::Layer,
|
||||
|
@ -750,7 +737,7 @@ EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet,
|
|||
changedPropertiesForAnimationLevel);
|
||||
if (!commonProperties.IsEmpty()) {
|
||||
EffectCompositor::RestyleType restyleType =
|
||||
compositorPropertiesInSet(changedPropertiesForAnimationLevel).none()
|
||||
changedPropertiesForAnimationLevel.Intersects(compositorAnimatables)
|
||||
? EffectCompositor::RestyleType::Standard
|
||||
: EffectCompositor::RestyleType::Layer;
|
||||
presContext->EffectCompositor()->
|
||||
|
|
|
@ -1242,29 +1242,33 @@ KeyframeEffect::CanThrottle() const
|
|||
return true;
|
||||
}
|
||||
|
||||
// First we need to check layer generation and transform overflow
|
||||
// prior to the property.mIsRunningOnCompositor check because we should
|
||||
// occasionally unthrottle these animations even if the animations are
|
||||
// already running on compositor.
|
||||
for (const LayerAnimationInfo::Record& record :
|
||||
LayerAnimationInfo::sRecords) {
|
||||
// Skip properties that are overridden by !important rules.
|
||||
// (GetEffectiveAnimationOfProperty, as called by
|
||||
// HasEffectiveAnimationOfProperty, only returns a property which is
|
||||
// neither overridden by !important rules nor overridden by other
|
||||
// animation.)
|
||||
if (!HasEffectiveAnimationOfProperty(record.mProperty)) {
|
||||
continue;
|
||||
EffectSet* effectSet = nullptr;
|
||||
for (const AnimationProperty& property : mProperties) {
|
||||
if (!property.mIsRunningOnCompositor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
|
||||
mTarget->mPseudoType);
|
||||
MOZ_ASSERT(effectSet, "CanThrottle should be called on an effect "
|
||||
"associated with a target element");
|
||||
MOZ_ASSERT(nsCSSPropertyIDSet::CompositorAnimatables()
|
||||
.HasProperty(property.mProperty),
|
||||
"The property should be able to run on the compositor");
|
||||
MOZ_ASSERT(HasEffectiveAnimationOfProperty(property.mProperty),
|
||||
"There should be an effective animation of the property while "
|
||||
"it is marked as being run on the compositor");
|
||||
|
||||
if (!effectSet) {
|
||||
effectSet = EffectSet::GetEffectSet(mTarget->mElement,
|
||||
mTarget->mPseudoType);
|
||||
MOZ_ASSERT(effectSet, "CanThrottle should be called on an effect "
|
||||
"associated with a target element");
|
||||
}
|
||||
|
||||
DisplayItemType displayItemType =
|
||||
LayerAnimationInfo::GetDisplayItemTypeForProperty(property.mProperty);
|
||||
|
||||
// Note that AnimationInfo::GetGenarationFromFrame() is supposed to work
|
||||
// with the primary frame instead of the style frame.
|
||||
Maybe<uint64_t> generation = layers::AnimationInfo::GetGenerationFromFrame(
|
||||
GetPrimaryFrame(), record.mLayerType);
|
||||
GetPrimaryFrame(), displayItemType);
|
||||
// Unthrottle if the animation needs to be brought up to date
|
||||
if (!generation || effectSet->GetAnimationGeneration() != *generation) {
|
||||
return false;
|
||||
|
@ -1278,12 +1282,6 @@ KeyframeEffect::CanThrottle() const
|
|||
}
|
||||
}
|
||||
|
||||
for (const AnimationProperty& property : mProperties) {
|
||||
if (!property.mIsRunningOnCompositor) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,8 @@ class ContentBlockingLog final
|
|||
// Each element is a tuple of (type, blocked, repeatCount). The type values
|
||||
// come from the blocking types defined in nsIWebProgressListener.
|
||||
typedef nsTArray<LogEntry> OriginLog;
|
||||
typedef nsClassHashtable<nsStringHashKey, OriginLog> OriginLogHashTable;
|
||||
typedef Pair<bool, OriginLog> OriginData;
|
||||
typedef nsClassHashtable<nsStringHashKey, OriginData> OriginDataHashTable;
|
||||
|
||||
struct StringWriteFunc : public JSONWriteFunc
|
||||
{
|
||||
|
@ -56,9 +57,14 @@ public:
|
|||
}
|
||||
auto entry = mLog.LookupForAdd(aOrigin);
|
||||
if (entry) {
|
||||
auto& log = entry.Data();
|
||||
if (!log->IsEmpty()) {
|
||||
auto& last = log->LastElement();
|
||||
auto& data = entry.Data();
|
||||
if (aType == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
|
||||
data->first() = aBlocked;
|
||||
return;
|
||||
}
|
||||
auto& log = data->second();
|
||||
if (!log.IsEmpty()) {
|
||||
auto& last = log.LastElement();
|
||||
if (last.mType == aType &&
|
||||
last.mBlocked == aBlocked) {
|
||||
++last.mRepeatCount;
|
||||
|
@ -66,17 +72,21 @@ public:
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (log->Length() ==
|
||||
if (log.Length() ==
|
||||
std::max(1u, StaticPrefs::browser_contentblocking_originlog_length())) {
|
||||
// Cap the size at the maximum length adjustable by the pref
|
||||
log->RemoveElementAt(0);
|
||||
log.RemoveElementAt(0);
|
||||
}
|
||||
log->AppendElement(LogEntry{aType, 1u, aBlocked});
|
||||
log.AppendElement(LogEntry{aType, 1u, aBlocked});
|
||||
} else {
|
||||
entry.OrInsert([=] {
|
||||
auto log(MakeUnique<OriginLog>());
|
||||
log->AppendElement(LogEntry{aType, 1u, aBlocked});
|
||||
return log.release();
|
||||
nsAutoPtr<OriginData> data(new OriginData(false, OriginLog()));
|
||||
if (aType == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
|
||||
data->first() = true;
|
||||
} else {
|
||||
data->second().AppendElement(LogEntry{aType, 1u, aBlocked});
|
||||
}
|
||||
return data.forget();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +106,17 @@ public:
|
|||
}
|
||||
|
||||
w.StartArrayProperty(NS_ConvertUTF16toUTF8(iter.Key()).get(), w.SingleLineStyle);
|
||||
for (auto& item: *iter.UserData()) {
|
||||
auto& data = *iter.UserData();
|
||||
if (data.first()) {
|
||||
w.StartArrayElement(w.SingleLineStyle);
|
||||
{
|
||||
w.IntElement(nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT);
|
||||
w.BoolElement(true); // blocked
|
||||
w.IntElement(1); // repeat count
|
||||
}
|
||||
w.EndArray();
|
||||
}
|
||||
for (auto& item: data.second()) {
|
||||
w.StartArrayElement(w.SingleLineStyle);
|
||||
{
|
||||
w.IntElement(item.mType);
|
||||
|
@ -120,10 +140,16 @@ public:
|
|||
continue;
|
||||
}
|
||||
|
||||
for (auto& item: *iter.UserData()) {
|
||||
if ((item.mType & aType) != 0) {
|
||||
if (aType == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
|
||||
if (iter.UserData()->first()) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
for (auto& item: iter.UserData()->second()) {
|
||||
if ((item.mType & aType) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -136,17 +162,17 @@ public:
|
|||
// Now add the sizes of each origin log queue.
|
||||
// The const_cast is needed because the nsTHashtable::Iterator interface is
|
||||
// not const-safe. :-(
|
||||
for (auto iter = const_cast<OriginLogHashTable&>(mLog).Iter();
|
||||
for (auto iter = const_cast<OriginDataHashTable&>(mLog).Iter();
|
||||
!iter.Done(); iter.Next()) {
|
||||
if (iter.UserData()) {
|
||||
aSizes.mDOMOtherSize +=
|
||||
iter.UserData()->ShallowSizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
|
||||
iter.UserData()->second().ShallowSizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OriginLogHashTable mLog;
|
||||
OriginDataHashTable mLog;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -102,14 +102,16 @@ void
|
|||
nsDOMNavigationTiming::NotifyUnloadEventStart()
|
||||
{
|
||||
mUnloadStart = TimeStamp::Now();
|
||||
PROFILER_TRACING("Navigation", "Unload", TRACING_INTERVAL_START);
|
||||
PROFILER_TRACING_DOCSHELL(
|
||||
"Navigation", "Unload", TRACING_INTERVAL_START, mDocShell);
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMNavigationTiming::NotifyUnloadEventEnd()
|
||||
{
|
||||
mUnloadEnd = TimeStamp::Now();
|
||||
PROFILER_TRACING("Navigation", "Unload", TRACING_INTERVAL_END);
|
||||
PROFILER_TRACING_DOCSHELL(
|
||||
"Navigation", "Unload", TRACING_INTERVAL_END, mDocShell);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -120,7 +122,8 @@ nsDOMNavigationTiming::NotifyLoadEventStart()
|
|||
}
|
||||
mLoadEventStart = TimeStamp::Now();
|
||||
|
||||
PROFILER_TRACING("Navigation", "Load", TRACING_INTERVAL_START);
|
||||
PROFILER_TRACING_DOCSHELL(
|
||||
"Navigation", "Load", TRACING_INTERVAL_START, mDocShell);
|
||||
|
||||
if (IsTopLevelContentDocumentInContentProcess()) {
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
|
@ -151,7 +154,8 @@ nsDOMNavigationTiming::NotifyLoadEventEnd()
|
|||
}
|
||||
mLoadEventEnd = TimeStamp::Now();
|
||||
|
||||
PROFILER_TRACING("Navigation", "Load", TRACING_INTERVAL_END);
|
||||
PROFILER_TRACING_DOCSHELL(
|
||||
"Navigation", "Load", TRACING_INTERVAL_END, mDocShell);
|
||||
|
||||
if (IsTopLevelContentDocumentInContentProcess()) {
|
||||
Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_LOAD_EVENT_END_MS,
|
||||
|
@ -215,7 +219,8 @@ nsDOMNavigationTiming::NotifyDOMContentLoadedStart(nsIURI* aURI)
|
|||
mLoadedURI = aURI;
|
||||
mDOMContentLoadedEventStart = TimeStamp::Now();
|
||||
|
||||
PROFILER_TRACING("Navigation", "DOMContentLoaded", TRACING_INTERVAL_START);
|
||||
PROFILER_TRACING_DOCSHELL(
|
||||
"Navigation", "DOMContentLoaded", TRACING_INTERVAL_START, mDocShell);
|
||||
|
||||
if (IsTopLevelContentDocumentInContentProcess()) {
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
|
@ -248,7 +253,8 @@ nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI)
|
|||
mLoadedURI = aURI;
|
||||
mDOMContentLoadedEventEnd = TimeStamp::Now();
|
||||
|
||||
PROFILER_TRACING("Navigation", "DOMContentLoaded", TRACING_INTERVAL_END);
|
||||
PROFILER_TRACING_DOCSHELL(
|
||||
"Navigation", "DOMContentLoaded", TRACING_INTERVAL_END, mDocShell);
|
||||
|
||||
if (IsTopLevelContentDocumentInContentProcess()) {
|
||||
Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_DOM_CONTENT_LOADED_END_MS,
|
||||
|
@ -356,8 +362,12 @@ nsDOMNavigationTiming::TTITimeout(nsITimer* aTimer)
|
|||
int(elapsed.ToMilliseconds()),
|
||||
int(elapsedLongTask.ToMilliseconds()),spec.get());
|
||||
|
||||
DECLARE_DOCSHELL_AND_HISTORY_ID(mDocShell);
|
||||
profiler_add_marker(
|
||||
"TTI", MakeUnique<UserTimingMarkerPayload>(NS_ConvertASCIItoUTF16(marker), mTTFI));
|
||||
"TTI", MakeUnique<UserTimingMarkerPayload>(NS_ConvertASCIItoUTF16(marker),
|
||||
mTTFI,
|
||||
docShellId,
|
||||
docShellHistoryId));
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
|
|
|
@ -259,6 +259,7 @@
|
|||
#include "mozilla/dom/TabGroup.h"
|
||||
#ifdef MOZ_XUL
|
||||
#include "mozilla/dom/XULBroadcastManager.h"
|
||||
#include "mozilla/dom/XULPersist.h"
|
||||
#include "mozilla/dom/TreeBoxObject.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsXULCommandDispatcher.h"
|
||||
|
@ -1737,6 +1738,10 @@ nsDocument::~nsDocument()
|
|||
mXULBroadcastManager->DropDocumentReference();
|
||||
}
|
||||
|
||||
if (mXULPersist) {
|
||||
mXULPersist->DropDocumentReference();
|
||||
}
|
||||
|
||||
delete mHeaderData;
|
||||
|
||||
ClearAllBoxObjects();
|
||||
|
@ -8972,6 +8977,13 @@ nsIDocument::SetReadyStateInternal(ReadyState rs)
|
|||
}
|
||||
|
||||
if (READYSTATE_INTERACTIVE == rs) {
|
||||
if (nsContentUtils::IsSystemPrincipal(NodePrincipal())) {
|
||||
Element* root = GetRootElement();
|
||||
if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozpersist)) {
|
||||
mXULPersist = new XULPersist(this);
|
||||
mXULPersist->Init();
|
||||
}
|
||||
}
|
||||
TriggerInitialDocumentTranslation();
|
||||
}
|
||||
|
||||
|
|
|
@ -562,6 +562,7 @@ SetTreeOwnerAndChromeEventHandlerOnDocshellTree(nsIDocShellTreeItem* aItem,
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
|
||||
static bool
|
||||
CheckDocShellType(mozilla::dom::Element* aOwnerContent,
|
||||
nsIDocShellTreeItem* aDocShell,
|
||||
|
@ -586,6 +587,7 @@ CheckDocShellType(mozilla::dom::Element* aOwnerContent,
|
|||
|
||||
return parent && parent->ItemType() == aDocShell->ItemType();
|
||||
}
|
||||
#endif // defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
|
||||
|
||||
/**
|
||||
* Hook up a given TreeItem to its tree owner. aItem's type must have already
|
||||
|
|
|
@ -149,6 +149,7 @@ class AnonymousContent;
|
|||
class Attr;
|
||||
class BoxObject;
|
||||
class XULBroadcastManager;
|
||||
class XULPersist;
|
||||
class ClientInfo;
|
||||
class ClientState;
|
||||
class CDATASection;
|
||||
|
@ -4756,6 +4757,7 @@ protected:
|
|||
nsCOMPtr<nsIDOMXULCommandDispatcher> mCommandDispatcher; // [OWNER] of the focus tracker
|
||||
|
||||
RefPtr<mozilla::dom::XULBroadcastManager> mXULBroadcastManager;
|
||||
RefPtr<mozilla::dom::XULPersist> mXULPersist;
|
||||
|
||||
// At the moment, trackers might be blocked by Tracking Protection or FastBlock.
|
||||
// In order to know the numbers of trackers detected and blocked, we add
|
||||
|
|
|
@ -1612,7 +1612,10 @@ nsObjectLoadingContent::UpdateObjectParameters()
|
|||
thisElement->GetAttr(kNameSpaceID_None, nsGkAtoms::type, rawTypeAttr);
|
||||
if (!rawTypeAttr.IsEmpty()) {
|
||||
typeAttr = rawTypeAttr;
|
||||
CopyUTF16toUTF8(rawTypeAttr, newMime);
|
||||
nsAutoString params;
|
||||
nsAutoString mime;
|
||||
nsContentUtils::SplitMimeType(rawTypeAttr, mime, params);
|
||||
CopyUTF16toUTF8(mime, newMime);
|
||||
}
|
||||
|
||||
// If we failed to build a valid URI, use the document's base URI
|
||||
|
|
|
@ -237,6 +237,7 @@ support-files =
|
|||
PASS.html
|
||||
FAIL.html
|
||||
!/dom/events/test/event_leak_utils.js
|
||||
../../../browser/extensions/pdfjs/test/file_pdfjs_test.pdf
|
||||
|
||||
[test_anchor_area_referrer.html]
|
||||
[test_anchor_area_referrer_changing.html]
|
||||
|
@ -617,6 +618,8 @@ skip-if = toolkit == 'android'
|
|||
[test_bug1453693.html]
|
||||
skip-if = os == "mac"
|
||||
[test_bug1472427.html]
|
||||
[test_bug1499169.html]
|
||||
skip-if = toolkit == 'android' # Timeouts on android due to page closing issues with embedded pdf
|
||||
[test_caretPositionFromPoint.html]
|
||||
[test_change_policy.html]
|
||||
[test_clearTimeoutIntervalNoArg.html]
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1499139
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1499169</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SpecialPowers.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function test() {
|
||||
const OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
|
||||
let obj = document.getElementById("pdftest");
|
||||
|
||||
obj instanceof OBJLC;
|
||||
obj = SpecialPowers.wrap(obj);
|
||||
|
||||
// Make sure we've set our type correctly even though the mime type isn't quite as expected.
|
||||
ok(obj.displayedType == OBJLC.TYPE_DOCUMENT, "expected document type");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1499169">Mozilla Bug 1499169</a>
|
||||
<object id="pdftest" onload="test()" data="file_pdfjs_test.pdf" type="application/pdf;charset=UTF-8" width="90%" height="600"></object>
|
||||
</body>
|
||||
</html>
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "nsPresContext.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsError.h"
|
||||
#include <new>
|
||||
#include "nsIContent.h"
|
||||
|
@ -1134,12 +1135,17 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
|
||||
"EventDispatcher::Dispatch", OTHER, typeStr);
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
docShell = nsContentUtils::GetDocShellForEventTarget(aEvent->mTarget);
|
||||
DECLARE_DOCSHELL_AND_HISTORY_ID(docShell);
|
||||
profiler_add_marker(
|
||||
"DOMEvent",
|
||||
MakeUnique<DOMEventMarkerPayload>(typeStr,
|
||||
aEvent->mTimeStamp,
|
||||
"DOMEvent",
|
||||
TRACING_INTERVAL_START));
|
||||
TRACING_INTERVAL_START,
|
||||
docShellId,
|
||||
docShellHistoryId));
|
||||
|
||||
EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
|
||||
aCallback, cd);
|
||||
|
@ -1149,7 +1155,9 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
MakeUnique<DOMEventMarkerPayload>(typeStr,
|
||||
aEvent->mTimeStamp,
|
||||
"DOMEvent",
|
||||
TRACING_INTERVAL_END));
|
||||
TRACING_INTERVAL_END,
|
||||
docShellId,
|
||||
docShellHistoryId));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
|
|
@ -2991,7 +2991,7 @@ ContentChild::StartForceKillTimer()
|
|||
return;
|
||||
}
|
||||
|
||||
int32_t timeoutSecs = Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5);
|
||||
int32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
|
||||
if (timeoutSecs > 0) {
|
||||
NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer),
|
||||
ContentChild::ForceKillTimerCallback,
|
||||
|
|
|
@ -1933,7 +1933,7 @@ ContentParent::StartForceKillTimer()
|
|||
return;
|
||||
}
|
||||
|
||||
int32_t timeoutSecs = Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5);
|
||||
int32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
|
||||
if (timeoutSecs > 0) {
|
||||
NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer),
|
||||
ContentParent::ForceKillTimerCallback,
|
||||
|
|
|
@ -154,13 +154,13 @@ OpusDataDecoder::DecodeHeader(const unsigned char* aData, size_t aLength)
|
|||
|
||||
AutoTArray<uint8_t, 8> map;
|
||||
map.SetLength(channels);
|
||||
if (vorbisLayout.MappingTable(smpteLayout, &map)) {
|
||||
if (mOpusParser->mChannelMapping == 1 &&
|
||||
vorbisLayout.MappingTable(smpteLayout, &map)) {
|
||||
for (int i = 0; i < channels; i++) {
|
||||
mMappingTable[i] = mOpusParser->mMappingTable[map[i]];
|
||||
}
|
||||
} else {
|
||||
// Should never get here as vorbis layout is always convertible to SMPTE
|
||||
// default layout.
|
||||
// Use Opus set channel mapping and return channels as-is.
|
||||
PodCopy(mMappingTable.Elements(), mOpusParser->mMappingTable, channels);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "Performance.h"
|
||||
|
||||
#include "GeckoProfiler.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsRFPService.h"
|
||||
#include "PerformanceEntry.h"
|
||||
#include "PerformanceMainThread.h"
|
||||
|
@ -249,9 +250,14 @@ Performance::Mark(const nsAString& aName, ErrorResult& aRv)
|
|||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
if (profiler_is_active()) {
|
||||
nsCOMPtr<EventTarget> et = do_QueryInterface(GetOwner());
|
||||
nsCOMPtr<nsIDocShell> docShell =
|
||||
nsContentUtils::GetDocShellForEventTarget(et);
|
||||
DECLARE_DOCSHELL_AND_HISTORY_ID(docShell);
|
||||
profiler_add_marker(
|
||||
"UserTiming",
|
||||
MakeUnique<UserTimingMarkerPayload>(aName, TimeStamp::Now()));
|
||||
MakeUnique<UserTimingMarkerPayload>(
|
||||
aName, TimeStamp::Now(), docShellId, docShellHistoryId));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -347,10 +353,18 @@ Performance::Measure(const nsAString& aName,
|
|||
endMark.emplace(aEndMark.Value());
|
||||
}
|
||||
|
||||
profiler_add_marker(
|
||||
"UserTiming",
|
||||
MakeUnique<UserTimingMarkerPayload>(aName, startMark, endMark,
|
||||
startTimeStamp, endTimeStamp));
|
||||
nsCOMPtr<EventTarget> et = do_QueryInterface(GetOwner());
|
||||
nsCOMPtr<nsIDocShell> docShell =
|
||||
nsContentUtils::GetDocShellForEventTarget(et);
|
||||
DECLARE_DOCSHELL_AND_HISTORY_ID(docShell);
|
||||
profiler_add_marker("UserTiming",
|
||||
MakeUnique<UserTimingMarkerPayload>(aName,
|
||||
startMark,
|
||||
endMark,
|
||||
startTimeStamp,
|
||||
endTimeStamp,
|
||||
docShellId,
|
||||
docShellHistoryId));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
#include "mozilla/dom/ProcessingInstruction.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/XULDocumentBinding.h"
|
||||
#include "mozilla/dom/XULPersist.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
@ -127,7 +128,6 @@ namespace dom {
|
|||
XULDocument::XULDocument(void)
|
||||
: XMLDocument("application/vnd.mozilla.xul+xml"),
|
||||
mNextSrcLoadWaiter(nullptr),
|
||||
mApplyingPersistedAttrs(false),
|
||||
mIsWritingFastLoad(false),
|
||||
mDocumentLoaded(false),
|
||||
mStillWalking(false),
|
||||
|
@ -201,12 +201,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XULDocument, XMLDocument)
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentPrototype)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototypes)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStore)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XULDocument, XMLDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStore)
|
||||
//XXX We should probably unlink all the objects we traverse.
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
@ -423,58 +421,6 @@ XULDocument::OnPrototypeLoadDone(bool aResumeWalk)
|
|||
return rv;
|
||||
}
|
||||
|
||||
static bool
|
||||
ShouldPersistAttribute(Element* aElement, nsAtom* aAttribute)
|
||||
{
|
||||
if (aElement->IsXULElement(nsGkAtoms::window)) {
|
||||
// This is not an element of the top document, its owner is
|
||||
// not an nsXULWindow. Persist it.
|
||||
if (aElement->OwnerDoc()->GetParentDocument()) {
|
||||
return true;
|
||||
}
|
||||
// The following attributes of xul:window should be handled in
|
||||
// nsXULWindow::SavePersistentAttributes instead of here.
|
||||
if (aAttribute == nsGkAtoms::screenX ||
|
||||
aAttribute == nsGkAtoms::screenY ||
|
||||
aAttribute == nsGkAtoms::width ||
|
||||
aAttribute == nsGkAtoms::height ||
|
||||
aAttribute == nsGkAtoms::sizemode) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute, int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
NS_ASSERTION(aElement->OwnerDoc() == this, "unexpected doc");
|
||||
|
||||
// Might not need this, but be safe for now.
|
||||
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
|
||||
|
||||
// See if there is anything we need to persist in the localstore.
|
||||
//
|
||||
// XXX Namespace handling broken :-(
|
||||
nsAutoString persist;
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist);
|
||||
// Persistence of attributes of xul:window is handled in nsXULWindow.
|
||||
if (ShouldPersistAttribute(aElement, aAttribute) && !persist.IsEmpty() &&
|
||||
// XXXldb This should check that it's a token, not just a substring.
|
||||
persist.Find(nsDependentAtomString(aAttribute)) >= 0) {
|
||||
nsContentUtils::AddScriptRunner(
|
||||
NewRunnableMethod<Element*, int32_t, nsAtom*>(
|
||||
"dom::XULDocument::Persist",
|
||||
this,
|
||||
&XULDocument::Persist,
|
||||
aElement,
|
||||
kNameSpaceID_None,
|
||||
aAttribute));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::ContentAppended(nsIContent* aFirstNewContent)
|
||||
{
|
||||
|
@ -513,58 +459,6 @@ XULDocument::ContentRemoved(nsIContent* aChild, nsIContent* aPreviousSibling)
|
|||
// nsIDocument interface
|
||||
//
|
||||
|
||||
|
||||
void
|
||||
XULDocument::Persist(Element* aElement, int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute)
|
||||
{
|
||||
// For non-chrome documents, persistance is simply broken
|
||||
if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()))
|
||||
return;
|
||||
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoString id;
|
||||
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
|
||||
nsAtomString attrstr(aAttribute);
|
||||
|
||||
nsAutoString valuestr;
|
||||
aElement->GetAttr(kNameSpaceID_None, aAttribute, valuestr);
|
||||
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocumentURI->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
bool hasAttr;
|
||||
rv = mLocalStore->HasValue(uri, id, attrstr, &hasAttr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasAttr && valuestr.IsEmpty()) {
|
||||
mLocalStore->RemoveValue(uri, id, attrstr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Persisting attributes to top level windows is handled by nsXULWindow.
|
||||
if (aElement->IsXULElement(nsGkAtoms::window)) {
|
||||
if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mLocalStore->SetValue(uri, id, attrstr, valuestr);
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::AddElementToDocumentPost(Element* aElement)
|
||||
{
|
||||
|
@ -721,145 +615,6 @@ XULDocument::PrepareToLoadPrototype(nsIURI* aURI, const char* aCommand,
|
|||
}
|
||||
|
||||
|
||||
nsresult
|
||||
XULDocument::ApplyPersistentAttributes()
|
||||
{
|
||||
// For non-chrome documents, persistance is simply broken
|
||||
if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// Add all of the 'persisted' attributes into the content
|
||||
// model.
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
mApplyingPersistedAttrs = true;
|
||||
ApplyPersistentAttributesInternal();
|
||||
mApplyingPersistedAttrs = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
XULDocument::ApplyPersistentAttributesInternal()
|
||||
{
|
||||
nsCOMArray<Element> elements;
|
||||
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocumentURI->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
// Get a list of element IDs for which persisted values are available
|
||||
nsCOMPtr<nsIStringEnumerator> ids;
|
||||
rv = mLocalStore->GetIDsEnumerator(uri, getter_AddRefs(ids));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
bool hasmore = false;
|
||||
ids->HasMore(&hasmore);
|
||||
if (!hasmore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString id;
|
||||
ids->GetNext(id);
|
||||
|
||||
nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(id);
|
||||
if (!entry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We want to hold strong refs to the elements while applying
|
||||
// persistent attributes, just in case.
|
||||
elements.Clear();
|
||||
elements.SetCapacity(entry->GetIdElements().Length());
|
||||
for (Element* element : entry->GetIdElements()) {
|
||||
elements.AppendObject(element);
|
||||
}
|
||||
if (elements.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rv = ApplyPersistentAttributesToElements(id, elements);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULDocument::ApplyPersistentAttributesToElements(const nsAString &aID,
|
||||
nsCOMArray<Element>& aElements)
|
||||
{
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocumentURI->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
// Get a list of attributes for which persisted values are available
|
||||
nsCOMPtr<nsIStringEnumerator> attrs;
|
||||
rv = mLocalStore->GetAttributeEnumerator(uri, aID, getter_AddRefs(attrs));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
bool hasmore = PR_FALSE;
|
||||
attrs->HasMore(&hasmore);
|
||||
if (!hasmore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString attrstr;
|
||||
attrs->GetNext(attrstr);
|
||||
|
||||
nsAutoString value;
|
||||
rv = mLocalStore->GetValue(uri, aID, attrstr, value);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
RefPtr<nsAtom> attr = NS_Atomize(attrstr);
|
||||
if (NS_WARN_IF(!attr)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
uint32_t cnt = aElements.Count();
|
||||
for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
|
||||
RefPtr<Element> element = aElements.SafeObjectAt(i);
|
||||
if (!element) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Applying persistent attributes to top level windows is handled
|
||||
// by nsXULWindow.
|
||||
if (element->IsXULElement(nsGkAtoms::window)) {
|
||||
if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Unused << element->SetAttr(kNameSpaceID_None, attr, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::TraceProtos(JSTracer* aTrc)
|
||||
{
|
||||
|
@ -1282,7 +1037,8 @@ XULDocument::ResumeWalk()
|
|||
// If we get here, there is nothing left for us to walk. The content
|
||||
// model is built and ready for layout.
|
||||
|
||||
ApplyPersistentAttributes();
|
||||
mXULPersist = new XULPersist(this);
|
||||
mXULPersist->Init();
|
||||
|
||||
mStillWalking = false;
|
||||
if (mPendingSheets == 0) {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "nsIStreamListener.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "nsICSSLoaderObserver.h"
|
||||
#include "nsIXULStore.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/ScriptLoader.h"
|
||||
|
@ -83,7 +82,6 @@ public:
|
|||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
|
||||
/**
|
||||
* Notify the XUL document that a subtree has been added
|
||||
|
@ -146,11 +144,6 @@ protected:
|
|||
nsIPrincipal* aDocumentPrincipal,
|
||||
nsIParser** aResult);
|
||||
|
||||
nsresult ApplyPersistentAttributes();
|
||||
nsresult ApplyPersistentAttributesInternal();
|
||||
nsresult ApplyPersistentAttributesToElements(const nsAString &aID,
|
||||
nsCOMArray<Element>& aElements);
|
||||
|
||||
void AddElementToDocumentPost(Element* aElement);
|
||||
|
||||
static void DirectionChanged(const char* aPrefName, XULDocument* aData);
|
||||
|
@ -160,11 +153,6 @@ protected:
|
|||
|
||||
static LazyLogModule gXULLog;
|
||||
|
||||
void
|
||||
Persist(mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute);
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// IMPORTANT: The ownership implicit in the following member
|
||||
|
@ -177,8 +165,6 @@ protected:
|
|||
|
||||
XULDocument* mNextSrcLoadWaiter; // [OWNER] but not COMPtr
|
||||
|
||||
nsCOMPtr<nsIXULStore> mLocalStore;
|
||||
bool mApplyingPersistedAttrs;
|
||||
bool mIsWritingFastLoad;
|
||||
bool mDocumentLoaded;
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "XULPersist.h"
|
||||
|
||||
#include "nsIXULStore.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static bool
|
||||
ShouldPersistAttribute(Element* aElement, nsAtom* aAttribute)
|
||||
{
|
||||
if (aElement->IsXULElement(nsGkAtoms::window)) {
|
||||
// This is not an element of the top document, its owner is
|
||||
// not an nsXULWindow. Persist it.
|
||||
if (aElement->OwnerDoc()->GetParentDocument()) {
|
||||
return true;
|
||||
}
|
||||
// The following attributes of xul:window should be handled in
|
||||
// nsXULWindow::SavePersistentAttributes instead of here.
|
||||
if (aAttribute == nsGkAtoms::screenX ||
|
||||
aAttribute == nsGkAtoms::screenY ||
|
||||
aAttribute == nsGkAtoms::width ||
|
||||
aAttribute == nsGkAtoms::height ||
|
||||
aAttribute == nsGkAtoms::sizemode) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(XULPersist, nsIDocumentObserver)
|
||||
|
||||
XULPersist::XULPersist(nsIDocument* aDocument)
|
||||
: nsStubDocumentObserver(),
|
||||
mDocument(aDocument)
|
||||
{
|
||||
}
|
||||
|
||||
XULPersist::~XULPersist()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
XULPersist::Init()
|
||||
{
|
||||
ApplyPersistentAttributes();
|
||||
mDocument->AddObserver(this);
|
||||
}
|
||||
|
||||
void
|
||||
XULPersist::DropDocumentReference()
|
||||
{
|
||||
mDocument->RemoveObserver(this);
|
||||
mDocument = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
XULPersist::AttributeChanged(dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
NS_ASSERTION(aElement->OwnerDoc() == mDocument, "unexpected doc");
|
||||
|
||||
// Might not need this, but be safe for now.
|
||||
nsCOMPtr<nsIDocumentObserver> kungFuDeathGrip(this);
|
||||
|
||||
// See if there is anything we need to persist in the localstore.
|
||||
//
|
||||
// XXX Namespace handling broken :-(
|
||||
nsAutoString persist;
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist);
|
||||
// Persistence of attributes of xul:window is handled in nsXULWindow.
|
||||
if (ShouldPersistAttribute(aElement, aAttribute) && !persist.IsEmpty() &&
|
||||
// XXXldb This should check that it's a token, not just a substring.
|
||||
persist.Find(nsDependentAtomString(aAttribute)) >= 0) {
|
||||
nsContentUtils::AddScriptRunner(
|
||||
NewRunnableMethod<Element*, int32_t, nsAtom*>(
|
||||
"dom::XULPersist::Persist",
|
||||
this,
|
||||
&XULPersist::Persist,
|
||||
aElement,
|
||||
kNameSpaceID_None,
|
||||
aAttribute));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XULPersist::Persist(Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute)
|
||||
{
|
||||
if (!mDocument) {
|
||||
return;
|
||||
}
|
||||
// For non-chrome documents, persistance is simply broken
|
||||
if (!nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoString id;
|
||||
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
|
||||
nsAtomString attrstr(aAttribute);
|
||||
|
||||
nsAutoString valuestr;
|
||||
aElement->GetAttr(kNameSpaceID_None, aAttribute, valuestr);
|
||||
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocument->GetDocumentURI()->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
bool hasAttr;
|
||||
rv = mLocalStore->HasValue(uri, id, attrstr, &hasAttr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasAttr && valuestr.IsEmpty()) {
|
||||
mLocalStore->RemoveValue(uri, id, attrstr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Persisting attributes to top level windows is handled by nsXULWindow.
|
||||
if (aElement->IsXULElement(nsGkAtoms::window)) {
|
||||
if (nsCOMPtr<nsIXULWindow> win = mDocument->GetXULWindowIfToplevelChrome()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mLocalStore->SetValue(uri, id, attrstr, valuestr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULPersist::ApplyPersistentAttributes()
|
||||
{
|
||||
if (!mDocument) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
// For non-chrome documents, persistance is simply broken
|
||||
if (!nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal())) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Add all of the 'persisted' attributes into the content
|
||||
// model.
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
ApplyPersistentAttributesInternal();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULPersist::ApplyPersistentAttributesInternal()
|
||||
{
|
||||
nsCOMArray<Element> elements;
|
||||
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocument->GetDocumentURI()->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
// Get a list of element IDs for which persisted values are available
|
||||
nsCOMPtr<nsIStringEnumerator> ids;
|
||||
rv = mLocalStore->GetIDsEnumerator(uri, getter_AddRefs(ids));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
bool hasmore = false;
|
||||
ids->HasMore(&hasmore);
|
||||
if (!hasmore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString id;
|
||||
ids->GetNext(id);
|
||||
|
||||
// We want to hold strong refs to the elements while applying
|
||||
// persistent attributes, just in case.
|
||||
const nsTArray<Element*>* allElements = mDocument->GetAllElementsForId(id);
|
||||
if (!allElements) {
|
||||
continue;
|
||||
}
|
||||
elements.Clear();
|
||||
elements.SetCapacity(allElements->Length());
|
||||
for (Element* element : *allElements) {
|
||||
elements.AppendObject(element);
|
||||
}
|
||||
|
||||
rv = ApplyPersistentAttributesToElements(id, elements);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULPersist::ApplyPersistentAttributesToElements(const nsAString &aID,
|
||||
nsCOMArray<Element>& aElements)
|
||||
{
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocument->GetDocumentURI()->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
// Get a list of attributes for which persisted values are available
|
||||
nsCOMPtr<nsIStringEnumerator> attrs;
|
||||
rv = mLocalStore->GetAttributeEnumerator(uri, aID, getter_AddRefs(attrs));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
bool hasmore = PR_FALSE;
|
||||
attrs->HasMore(&hasmore);
|
||||
if (!hasmore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString attrstr;
|
||||
attrs->GetNext(attrstr);
|
||||
|
||||
nsAutoString value;
|
||||
rv = mLocalStore->GetValue(uri, aID, attrstr, value);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
RefPtr<nsAtom> attr = NS_Atomize(attrstr);
|
||||
if (NS_WARN_IF(!attr)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
uint32_t cnt = aElements.Length();
|
||||
for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
|
||||
Element* element = aElements.SafeElementAt(i);
|
||||
if (!element) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Applying persistent attributes to top level windows is handled
|
||||
// by nsXULWindow.
|
||||
if (element->IsXULElement(nsGkAtoms::window)) {
|
||||
if (nsCOMPtr<nsIXULWindow> win = mDocument->GetXULWindowIfToplevelChrome()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Unused << element->SetAttr(kNameSpaceID_None, attr, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_XULPersist_h
|
||||
#define mozilla_dom_XULPersist_h
|
||||
|
||||
class nsIXULStore;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class XULPersist final : public nsStubDocumentObserver
|
||||
{
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit XULPersist(nsIDocument* aDocument);
|
||||
void Init();
|
||||
void DropDocumentReference();
|
||||
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
|
||||
protected:
|
||||
|
||||
void Persist(mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute);
|
||||
|
||||
private:
|
||||
~XULPersist();
|
||||
nsresult ApplyPersistentAttributes();
|
||||
nsresult ApplyPersistentAttributesInternal();
|
||||
nsresult ApplyPersistentAttributesToElements(const nsAString &aID,
|
||||
nsCOMArray<Element>& aElements);
|
||||
|
||||
nsCOMPtr<nsIXULStore> mLocalStore;
|
||||
// A weak pointer to our document. Nulled out by DropDocumentReference.
|
||||
nsIDocument* MOZ_NON_OWNING_REF mDocument;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
#endif // mozilla_dom_XULPersist_h
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче