mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 20:05:49 +00:00
Merge mozilla-central and inbound
This commit is contained in:
commit
c57c578dc0
@ -764,7 +764,6 @@ var gBrowserInit = {
|
||||
window.addEventListener("AppCommand", HandleAppCommandEvent, true);
|
||||
|
||||
messageManager.loadFrameScript("chrome://browser/content/content.js", true);
|
||||
messageManager.loadFrameScript("chrome://browser/content/content-sessionStore.js", true);
|
||||
|
||||
// initialize observers and listeners
|
||||
// and give C++ access to gBrowser
|
||||
|
@ -2253,6 +2253,10 @@
|
||||
// Make sure to unregister any open URIs.
|
||||
this._swapRegisteredOpenURIs(ourBrowser, aOtherBrowser);
|
||||
|
||||
// Give others a chance to swap state.
|
||||
let event = new CustomEvent("SwapDocShells", {"detail": aOtherBrowser});
|
||||
ourBrowser.dispatchEvent(event);
|
||||
|
||||
// Swap the docshells
|
||||
ourBrowser.swapDocShells(aOtherBrowser);
|
||||
|
||||
|
@ -120,6 +120,48 @@ let MessageListener = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* If session data must be collected synchronously, we do it via
|
||||
* method calls to this object (rather than via messages to
|
||||
* MessageListener). When using multiple processes, these methods run
|
||||
* in the content process, but the parent synchronously waits on them
|
||||
* using cross-process object wrappers. Without multiple processes, we
|
||||
* still use this code for synchronous collection.
|
||||
*/
|
||||
let SyncHandler = {
|
||||
init: function () {
|
||||
// Send this object as a CPOW to chrome. In single-process mode,
|
||||
// the synchronous send ensures that the handler object is
|
||||
// available in SessionStore.jsm immediately upon loading
|
||||
// content-sessionStore.js.
|
||||
sendSyncMessage("SessionStore:setupSyncHandler", {}, {handler: this});
|
||||
},
|
||||
|
||||
collectSessionHistory: function (includePrivateData) {
|
||||
let history = SessionHistory.read(docShell);
|
||||
if ("index" in history) {
|
||||
let tabIndex = history.index - 1;
|
||||
TextAndScrollData.updateFrame(history.entries[tabIndex],
|
||||
content,
|
||||
docShell.isAppTab,
|
||||
{includePrivateData: includePrivateData});
|
||||
}
|
||||
return history;
|
||||
},
|
||||
|
||||
collectSessionStorage: function () {
|
||||
return SessionStorage.serialize(docShell);
|
||||
},
|
||||
|
||||
collectDocShellCapabilities: function () {
|
||||
return DocShellCapabilities.collect(docShell);
|
||||
},
|
||||
|
||||
collectPageStyle: function () {
|
||||
return PageStyle.collect(docShell);
|
||||
},
|
||||
};
|
||||
|
||||
let ProgressListener = {
|
||||
init: function() {
|
||||
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
@ -140,4 +182,5 @@ let ProgressListener = {
|
||||
|
||||
EventListener.init();
|
||||
MessageListener.init();
|
||||
SyncHandler.init();
|
||||
ProgressListener.init();
|
||||
|
@ -65,7 +65,11 @@ const MESSAGES = [
|
||||
|
||||
// The content script tells us that a new page just started loading in a
|
||||
// browser.
|
||||
"SessionStore:loadStart"
|
||||
"SessionStore:loadStart",
|
||||
|
||||
// The content script gives us a reference to an object that performs
|
||||
// synchronous collection of session data.
|
||||
"SessionStore:setupSyncHandler"
|
||||
];
|
||||
|
||||
// These are tab events that we listen to.
|
||||
@ -602,6 +606,9 @@ let SessionStoreInternal = {
|
||||
case "SessionStore:loadStart":
|
||||
TabStateCache.delete(browser);
|
||||
break;
|
||||
case "SessionStore:setupSyncHandler":
|
||||
TabState.setSyncHandler(browser, aMessage.objects.handler);
|
||||
break;
|
||||
default:
|
||||
debug("received unknown message '" + aMessage.name + "'");
|
||||
break;
|
||||
@ -620,17 +627,23 @@ let SessionStoreInternal = {
|
||||
return;
|
||||
|
||||
var win = aEvent.currentTarget.ownerDocument.defaultView;
|
||||
let browser;
|
||||
switch (aEvent.type) {
|
||||
case "load":
|
||||
// If __SS_restore_data is set, then we need to restore the document
|
||||
// (form data, scrolling, etc.). This will only happen when a tab is
|
||||
// first restored.
|
||||
let browser = aEvent.currentTarget;
|
||||
browser = aEvent.currentTarget;
|
||||
TabStateCache.delete(browser);
|
||||
if (browser.__SS_restore_data)
|
||||
this.restoreDocument(win, browser, aEvent);
|
||||
this.onTabLoad(win, browser);
|
||||
break;
|
||||
case "SwapDocShells":
|
||||
browser = aEvent.currentTarget;
|
||||
let otherBrowser = aEvent.detail;
|
||||
TabState.onSwapDocShells(browser, otherBrowser);
|
||||
break;
|
||||
case "TabOpen":
|
||||
this.onTabAdd(win, aEvent.originalTarget);
|
||||
break;
|
||||
@ -1203,10 +1216,14 @@ let SessionStoreInternal = {
|
||||
onTabAdd: function ssi_onTabAdd(aWindow, aTab, aNoNotification) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
browser.addEventListener("load", this, true);
|
||||
browser.addEventListener("SwapDocShells", this, true);
|
||||
|
||||
let mm = browser.messageManager;
|
||||
MESSAGES.forEach(msg => mm.addMessageListener(msg, this));
|
||||
|
||||
// Load the frame script after registering listeners.
|
||||
mm.loadFrameScript("chrome://browser/content/content-sessionStore.js", false);
|
||||
|
||||
if (!aNoNotification) {
|
||||
this.saveStateDelayed(aWindow);
|
||||
}
|
||||
@ -1226,6 +1243,7 @@ let SessionStoreInternal = {
|
||||
onTabRemove: function ssi_onTabRemove(aWindow, aTab, aNoNotification) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
browser.removeEventListener("load", this, true);
|
||||
browser.removeEventListener("SwapDocShells", this, true);
|
||||
|
||||
let mm = browser.messageManager;
|
||||
MESSAGES.forEach(msg => mm.removeMessageListener(msg, this));
|
||||
@ -4208,6 +4226,47 @@ let TabState = {
|
||||
// their promises when collecting tab data asynchronously.
|
||||
_pendingCollections: new WeakMap(),
|
||||
|
||||
// A map (xul:browser -> handler) that maps a tab to the
|
||||
// synchronous collection handler object for that tab.
|
||||
// See SyncHandler in content-sessionStore.js.
|
||||
_syncHandlers: new WeakMap(),
|
||||
|
||||
/**
|
||||
* Install the sync handler object from a given tab.
|
||||
*/
|
||||
setSyncHandler: function (browser, handler) {
|
||||
this._syncHandlers.set(browser, handler);
|
||||
},
|
||||
|
||||
/**
|
||||
* When a docshell swap happens, a xul:browser element will be
|
||||
* associated with a different content-sessionStore.js script
|
||||
* global. In this case, the sync handler for the element needs to
|
||||
* be swapped just like the docshell.
|
||||
*/
|
||||
onSwapDocShells: function (browser, otherBrowser) {
|
||||
// Make sure that one or the other of these has a sync handler,
|
||||
// and let it be |browser|.
|
||||
if (!this._syncHandlers.has(browser)) {
|
||||
[browser, otherBrowser] = [otherBrowser, browser];
|
||||
if (!this._syncHandlers.has(browser)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, browser is guaranteed to have a sync handler,
|
||||
// although otherBrowser may not. Perform the swap.
|
||||
let handler = this._syncHandlers.get(browser);
|
||||
if (this._syncHandlers.has(otherBrowser)) {
|
||||
let otherHandler = this._syncHandlers.get(otherBrowser);
|
||||
this._syncHandlers.set(browser, otherHandler);
|
||||
this._syncHandlers.set(otherHandler, handler);
|
||||
} else {
|
||||
this._syncHandlers.set(otherBrowser, handler);
|
||||
this._syncHandlers.delete(browser);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Collect data related to a single tab, asynchronously.
|
||||
*
|
||||
@ -4226,11 +4285,10 @@ let TabState = {
|
||||
return Promise.resolve(TabStateCache.get(tab));
|
||||
}
|
||||
|
||||
// If the tab hasn't been restored yet, just return the data we
|
||||
// have saved for it.
|
||||
let browser = tab.linkedBrowser;
|
||||
if (!browser.currentURI || (browser.__SS_data && browser.__SS_tabStillLoading)) {
|
||||
let tabData = new TabData(this._collectBaseTabData(tab));
|
||||
// If the tab was recently added, or if it's being restored, we
|
||||
// just collect basic data about it and skip the cache.
|
||||
if (!this._tabNeedsExtraCollection(tab)) {
|
||||
let tabData = this._collectBaseTabData(tab);
|
||||
return Promise.resolve(tabData);
|
||||
}
|
||||
|
||||
@ -4248,10 +4306,7 @@ let TabState = {
|
||||
let pageStyle = yield Messenger.send(tab, "SessionStore:collectPageStyle");
|
||||
|
||||
// Collect basic tab data, without session history and storage.
|
||||
let options = {omitSessionHistory: true,
|
||||
omitSessionStorage: true,
|
||||
omitDocShellCapabilities: true};
|
||||
let tabData = this._collectBaseTabData(tab, options);
|
||||
let tabData = this._collectBaseTabData(tab);
|
||||
|
||||
// Apply collected data.
|
||||
tabData.entries = history.entries;
|
||||
@ -4308,8 +4363,9 @@ let TabState = {
|
||||
return TabStateCache.get(tab);
|
||||
}
|
||||
|
||||
let tabData = this._collectBaseTabData(tab);
|
||||
if (this._updateTextAndScrollDataForTab(tab, tabData)) {
|
||||
let tabData = this._collectSyncUncached(tab);
|
||||
|
||||
if (this._tabCachingAllowed(tab)) {
|
||||
TabStateCache.set(tab, tabData);
|
||||
}
|
||||
|
||||
@ -4335,34 +4391,142 @@ let TabState = {
|
||||
* up-to-date.
|
||||
*/
|
||||
clone: function (tab) {
|
||||
let options = { includePrivateData: true };
|
||||
let tabData = this._collectBaseTabData(tab, options);
|
||||
this._updateTextAndScrollDataForTab(tab, tabData, options);
|
||||
return this._collectSyncUncached(tab, {includePrivateData: true});
|
||||
},
|
||||
|
||||
/**
|
||||
* Synchronously collect all session data for a tab. The
|
||||
* TabStateCache is not consulted, and the resulting data is not put
|
||||
* in the cache.
|
||||
*/
|
||||
_collectSyncUncached: function (tab, options = {}) {
|
||||
// Collect basic tab data, without session history and storage.
|
||||
let tabData = this._collectBaseTabData(tab);
|
||||
|
||||
// If we don't need any other data, return what we have.
|
||||
if (!this._tabNeedsExtraCollection(tab)) {
|
||||
return tabData;
|
||||
}
|
||||
|
||||
// In multiprocess Firefox, there is a small window of time after
|
||||
// tab creation when we haven't received a sync handler object. In
|
||||
// this case the tab shouldn't have any history or cookie data, so we
|
||||
// just return the base data already collected.
|
||||
if (!this._syncHandlers.has(tab.linkedBrowser)) {
|
||||
return tabData;
|
||||
}
|
||||
|
||||
let syncHandler = this._syncHandlers.get(tab.linkedBrowser);
|
||||
|
||||
let includePrivateData = options && options.includePrivateData;
|
||||
|
||||
let history, storage, disallow, pageStyle;
|
||||
try {
|
||||
history = syncHandler.collectSessionHistory(includePrivateData);
|
||||
storage = syncHandler.collectSessionStorage();
|
||||
disallow = syncHandler.collectDocShellCapabilities();
|
||||
pageStyle = syncHandler.collectPageStyle();
|
||||
} catch (e) {
|
||||
// This may happen if the tab has crashed.
|
||||
Cu.reportError(e);
|
||||
return tabData;
|
||||
}
|
||||
|
||||
tabData.entries = history.entries;
|
||||
if ("index" in history) {
|
||||
tabData.index = history.index;
|
||||
}
|
||||
|
||||
if (Object.keys(storage).length) {
|
||||
tabData.storage = storage;
|
||||
}
|
||||
|
||||
if (disallow.length > 0) {
|
||||
tabData.disallow = disallow.join(",");
|
||||
}
|
||||
|
||||
if (pageStyle) {
|
||||
tabData.pageStyle = pageStyle;
|
||||
}
|
||||
|
||||
return tabData;
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns true if the xul:tab element is newly added (i.e., if it's
|
||||
* showing about:blank with no history).
|
||||
*/
|
||||
_tabIsNew: function (tab) {
|
||||
let browser = tab.linkedBrowser;
|
||||
return (!browser || !browser.currentURI);
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns true if the xul:tab element is in the process of being
|
||||
* restored.
|
||||
*/
|
||||
_tabIsRestoring: function (tab) {
|
||||
let browser = tab.linkedBrowser;
|
||||
return (browser.__SS_data && browser.__SS_tabStillLoading);
|
||||
},
|
||||
|
||||
/**
|
||||
* This function returns true if we need to collect history, page
|
||||
* style, and text and scroll data from the tab. Normally we do. The
|
||||
* cases when we don't are:
|
||||
* 1. the tab is about:blank with no history, or
|
||||
* 2. the tab is waiting to be restored.
|
||||
*
|
||||
* @param tab A xul:tab element.
|
||||
* @returns True if the tab is in the process of being restored.
|
||||
*/
|
||||
_tabNeedsExtraCollection: function (tab) {
|
||||
if (this._tabIsNew(tab)) {
|
||||
// Tab is about:blank with no history.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this._tabIsRestoring(tab)) {
|
||||
// Tab is waiting to be restored.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise we need the extra data.
|
||||
return true;
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns true if we should cache the tabData for the given the
|
||||
* xul:tab element.
|
||||
*/
|
||||
_tabCachingAllowed: function (tab) {
|
||||
if (this._tabIsNew(tab)) {
|
||||
// No point in caching data for newly created tabs.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this._tabIsRestoring(tab)) {
|
||||
// If the tab is being restored, we just return the data being
|
||||
// restored. This data may be incomplete (if supplied by
|
||||
// setBrowserState, for example), so we don't want to cache it.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Collects basic tab data for a given tab.
|
||||
*
|
||||
* @param tab
|
||||
* tabbrowser tab
|
||||
* @param options
|
||||
* An object that will be passed to session history and session
|
||||
* storage data collection methods.
|
||||
* {omitSessionHistory: true} to skip collecting session history data
|
||||
* {omitSessionStorage: true} to skip collecting session storage data
|
||||
* {omitDocShellCapabilities: true} to skip collecting docShell allow* attributes
|
||||
*
|
||||
* The omit* options have been introduced to enable us collecting
|
||||
* those parts of the tab data asynchronously. We will request basic
|
||||
* tabData without the parts to omit and fill those holes later when
|
||||
* the content script has responded.
|
||||
*
|
||||
* @returns {object} An object with the basic data for this tab.
|
||||
*/
|
||||
_collectBaseTabData: function (tab, options = {}) {
|
||||
_collectBaseTabData: function (tab) {
|
||||
let tabData = {entries: [], lastAccessed: tab.lastAccessed };
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
if (!browser || !browser.currentURI) {
|
||||
// can happen when calling this function right after .addTab()
|
||||
return tabData;
|
||||
@ -4386,11 +4550,6 @@ let TabState = {
|
||||
return tabData;
|
||||
}
|
||||
|
||||
// Collection session history data.
|
||||
if (!options || !options.omitSessionHistory) {
|
||||
this._collectTabHistory(tab, tabData, options);
|
||||
}
|
||||
|
||||
// If there is a userTypedValue set, then either the user has typed something
|
||||
// in the URL bar, or a new tab was opened with a URI to load. userTypedClear
|
||||
// is used to indicate whether the tab was in some sort of loading state with
|
||||
@ -4409,14 +4568,6 @@ let TabState = {
|
||||
delete tabData.pinned;
|
||||
tabData.hidden = tab.hidden;
|
||||
|
||||
if (!options || !options.omitDocShellCapabilities) {
|
||||
let disallow = DocShellCapabilities.collect(browser.docShell);
|
||||
if (disallow.length > 0)
|
||||
tabData.disallow = disallow.join(",");
|
||||
else if (tabData.disallow)
|
||||
delete tabData.disallow;
|
||||
}
|
||||
|
||||
// Save tab attributes.
|
||||
tabData.attributes = TabAttributes.get(tab);
|
||||
|
||||
@ -4429,105 +4580,8 @@ let TabState = {
|
||||
else if (tabData.extData)
|
||||
delete tabData.extData;
|
||||
|
||||
// Collect DOMSessionStorage data.
|
||||
if (!options || !options.omitSessionStorage) {
|
||||
this._collectTabSessionStorage(tab, tabData, options);
|
||||
}
|
||||
|
||||
return tabData;
|
||||
},
|
||||
|
||||
/**
|
||||
* Collects session history data for a given tab.
|
||||
*
|
||||
* @param tab
|
||||
* tabbrowser tab
|
||||
* @param tabData
|
||||
* An object that the session history data will be added to.
|
||||
* @param options
|
||||
* {includePrivateData: true} to always include private data
|
||||
*/
|
||||
_collectTabHistory: function (tab, tabData, options = {}) {
|
||||
let includePrivateData = options && options.includePrivateData;
|
||||
let docShell = tab.linkedBrowser.docShell;
|
||||
|
||||
if (docShell instanceof Ci.nsIDocShell) {
|
||||
let history = SessionHistory.read(docShell, includePrivateData);
|
||||
tabData.entries = history.entries;
|
||||
|
||||
// For blank tabs without any history entries,
|
||||
// there will not be an 'index' property.
|
||||
if ("index" in history) {
|
||||
tabData.index = history.index;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Collects session history data for a given tab.
|
||||
*
|
||||
* @param tab
|
||||
* tabbrowser tab
|
||||
* @param tabData
|
||||
* An object that the session storage data will be added to.
|
||||
* @param options
|
||||
* {includePrivateData: true} to always include private data
|
||||
*/
|
||||
_collectTabSessionStorage: function (tab, tabData, options = {}) {
|
||||
let includePrivateData = options && options.includePrivateData;
|
||||
let docShell = tab.linkedBrowser.docShell;
|
||||
|
||||
if (docShell instanceof Ci.nsIDocShell) {
|
||||
let storageData = SessionStorage.serialize(docShell, includePrivateData)
|
||||
if (Object.keys(storageData).length) {
|
||||
tabData.storage = storageData;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Go through all frames and store the current scroll positions
|
||||
* and innerHTML content of WYSIWYG editors
|
||||
*
|
||||
* @param tab
|
||||
* tabbrowser tab
|
||||
* @param tabData
|
||||
* tabData object to add the information to
|
||||
* @param options
|
||||
* An optional object that may contain the following field:
|
||||
* - includePrivateData: always return privacy sensitive data
|
||||
* (use with care)
|
||||
* @return false if data should not be cached because the tab
|
||||
* has not been fully initialized yet.
|
||||
*/
|
||||
_updateTextAndScrollDataForTab: function (tab, tabData, options = null) {
|
||||
let includePrivateData = options && options.includePrivateData;
|
||||
let window = tab.ownerDocument.defaultView;
|
||||
let browser = tab.linkedBrowser;
|
||||
// we shouldn't update data for incompletely initialized tabs
|
||||
if (!browser.currentURI
|
||||
|| (browser.__SS_data && browser.__SS_tabStillLoading)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let tabIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
// entry data needn't exist for tabs just initialized with an incomplete session state
|
||||
if (!tabData.entries[tabIndex]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let selectedPageStyle = PageStyle.collect(browser.docShell);
|
||||
if (selectedPageStyle) {
|
||||
tabData.pageStyle = selectedPageStyle;
|
||||
}
|
||||
|
||||
TextAndScrollData.updateFrame(tabData.entries[tabIndex],
|
||||
browser.contentWindow,
|
||||
!!tabData.pinned,
|
||||
{includePrivateData: includePrivateData});
|
||||
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// The state from the previous session (after restoring pinned tabs). This
|
||||
|
347
content/media/webrtc/LoadMonitor.cpp
Normal file
347
content/media/webrtc/LoadMonitor.cpp
Normal file
@ -0,0 +1,347 @@
|
||||
/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "LoadMonitor.h"
|
||||
#include "nsString.h"
|
||||
#include "prlog.h"
|
||||
#include "prtime.h"
|
||||
#include "prinrval.h"
|
||||
#include "prsystem.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsILineInputStream.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#if defined(ANDROID) || defined(LINUX) || defined(XP_MACOSX)
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
// NSPR_LOG_MODULES=LoadMonitor:5
|
||||
PRLogModuleInfo *gLoadMonitorLog = nullptr;
|
||||
#if defined(PR_LOGGING)
|
||||
#define LOG(args) PR_LOG(gLoadMonitorLog, PR_LOG_DEBUG, args)
|
||||
#define LOG_ENABLED() PR_LOG_TEST(gLoadMonitorLog, 4)
|
||||
#define LOG_MANY_ENABLED() PR_LOG_TEST(gLoadMonitorLog, 5)
|
||||
#else
|
||||
#define LOG(args)
|
||||
#define LOG_ENABLED() (false)
|
||||
#define LOG_MANY_ENABLED() (false)
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// Update the system load every x milliseconds
|
||||
static const int kLoadUpdateInterval = 1000;
|
||||
|
||||
NS_IMPL_ISUPPORTS1(LoadMonitor, nsIObserver)
|
||||
|
||||
LoadMonitor::LoadMonitor()
|
||||
: mLock("LoadMonitor.mLock"),
|
||||
mCondVar(mLock, "LoadMonitor.mCondVar"),
|
||||
mShutdownPending(false),
|
||||
mLoadInfoThread(nullptr),
|
||||
mSystemLoad(0.0f),
|
||||
mProcessLoad(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
LoadMonitor::~LoadMonitor()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadMonitor::Observe(nsISupports* /* aSubject */,
|
||||
const char* aTopic,
|
||||
const PRUnichar* /* aData */)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(!strcmp("xpcom-shutdown-threads", aTopic), "Bad topic!");
|
||||
Shutdown();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class LoadMonitorAddObserver : public nsRunnable
|
||||
{
|
||||
public:
|
||||
LoadMonitorAddObserver(nsRefPtr<LoadMonitor> loadMonitor)
|
||||
{
|
||||
mLoadMonitor = loadMonitor;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (!observerService)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult rv = observerService->AddObserver(mLoadMonitor, "xpcom-shutdown-threads", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<LoadMonitor> mLoadMonitor;
|
||||
};
|
||||
|
||||
class LoadMonitorRemoveObserver : public nsRunnable
|
||||
{
|
||||
public:
|
||||
LoadMonitorRemoveObserver(nsRefPtr<LoadMonitor> loadMonitor)
|
||||
{
|
||||
mLoadMonitor = loadMonitor;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
// remove xpcom shutdown observer
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
if (observerService)
|
||||
observerService->RemoveObserver(mLoadMonitor, "xpcom-shutdown-threads");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<LoadMonitor> mLoadMonitor;
|
||||
};
|
||||
|
||||
void LoadMonitor::Shutdown()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
if (mLoadInfoThread) {
|
||||
mShutdownPending = true;
|
||||
mCondVar.Notify();
|
||||
|
||||
mLoadInfoThread = nullptr;
|
||||
|
||||
nsRefPtr<LoadMonitorRemoveObserver> remObsRunner = new LoadMonitorRemoveObserver(this);
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(remObsRunner, NS_DISPATCH_NORMAL);
|
||||
} else {
|
||||
remObsRunner->Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LoadStats
|
||||
{
|
||||
public:
|
||||
LoadStats() :
|
||||
mPrevTotalTimes(0),
|
||||
mPrevCpuTimes(0),
|
||||
mPrevLoad(0) {};
|
||||
|
||||
double GetLoad() { return (double)mPrevLoad; };
|
||||
|
||||
uint64_t mPrevTotalTimes;
|
||||
uint64_t mPrevCpuTimes;
|
||||
float mPrevLoad; // Previous load value.
|
||||
};
|
||||
|
||||
class LoadInfo : public mozilla::RefCounted<LoadInfo>
|
||||
{
|
||||
public:
|
||||
double GetSystemLoad() { return mSystemLoad.GetLoad(); };
|
||||
double GetProcessLoad() { return mProcessLoad.GetLoad(); };
|
||||
nsresult UpdateSystemLoad();
|
||||
nsresult UpdateProcessLoad();
|
||||
|
||||
private:
|
||||
void UpdateCpuLoad(uint64_t current_total_times,
|
||||
uint64_t current_cpu_times,
|
||||
LoadStats* loadStat);
|
||||
LoadStats mSystemLoad;
|
||||
LoadStats mProcessLoad;
|
||||
};
|
||||
|
||||
void LoadInfo::UpdateCpuLoad(uint64_t current_total_times,
|
||||
uint64_t current_cpu_times,
|
||||
LoadStats *loadStat) {
|
||||
float result = 0.0f;
|
||||
|
||||
if (current_total_times < loadStat->mPrevTotalTimes ||
|
||||
current_cpu_times < loadStat->mPrevCpuTimes) {
|
||||
//LOG(("Current total: %lld old total: %lld", current_total_times, loadStat->mPrevTotalTimes));
|
||||
//LOG(("Current cpu: %lld old cpu: %lld", current_cpu_times, loadStat->mPrevCpuTimes));
|
||||
LOG(("Inconsistent time values are passed. ignored"));
|
||||
} else {
|
||||
const uint64_t cpu_diff = current_cpu_times - loadStat->mPrevCpuTimes;
|
||||
const uint64_t total_diff = current_total_times - loadStat->mPrevTotalTimes;
|
||||
if (total_diff > 0) {
|
||||
result = (float)cpu_diff / (float)total_diff;
|
||||
loadStat->mPrevLoad = result;
|
||||
}
|
||||
}
|
||||
loadStat->mPrevTotalTimes = current_total_times;
|
||||
loadStat->mPrevCpuTimes = current_cpu_times;
|
||||
}
|
||||
|
||||
nsresult LoadInfo::UpdateSystemLoad()
|
||||
{
|
||||
#if defined(LINUX) || defined(ANDROID)
|
||||
nsCOMPtr<nsIFile> procStatFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
|
||||
procStatFile->InitWithPath(NS_LITERAL_STRING("/proc/stat"));
|
||||
|
||||
nsCOMPtr<nsIInputStream> fileInputStream;
|
||||
nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream),
|
||||
procStatFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString buffer;
|
||||
bool isMore = true;
|
||||
lineInputStream->ReadLine(buffer, &isMore);
|
||||
|
||||
uint64_t user;
|
||||
uint64_t nice;
|
||||
uint64_t system;
|
||||
uint64_t idle;
|
||||
if (sscanf(buffer.get(), "cpu %Lu %Lu %Lu %Lu",
|
||||
&user, &nice,
|
||||
&system, &idle) != 4) {
|
||||
LOG(("Error parsing /proc/stat"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
const uint64_t cpu_times = nice + system + user;
|
||||
const uint64_t total_times = cpu_times + idle;
|
||||
|
||||
UpdateCpuLoad(total_times,
|
||||
cpu_times * PR_GetNumberOfProcessors(),
|
||||
&mSystemLoad);
|
||||
return NS_OK;
|
||||
#else
|
||||
// Not implemented
|
||||
return NS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult LoadInfo::UpdateProcessLoad() {
|
||||
#if defined(LINUX) || defined(ANDROID)
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
const uint64_t total_times = tv.tv_sec * PR_USEC_PER_SEC + tv.tv_usec;
|
||||
|
||||
rusage usage;
|
||||
if (getrusage(RUSAGE_SELF, &usage) < 0) {
|
||||
LOG(("getrusage failed"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
const uint64_t cpu_times =
|
||||
(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * PR_USEC_PER_SEC +
|
||||
usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
|
||||
|
||||
UpdateCpuLoad(total_times,
|
||||
cpu_times,
|
||||
&mProcessLoad);
|
||||
#endif // defined(LINUX) || defined(ANDROID)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class LoadInfoCollectRunner : public nsRunnable
|
||||
{
|
||||
public:
|
||||
LoadInfoCollectRunner(nsRefPtr<LoadMonitor> loadMonitor)
|
||||
{
|
||||
mLoadMonitor = loadMonitor;
|
||||
mLoadInfo = new LoadInfo();
|
||||
mLoadNoiseCounter = 0;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MutexAutoLock lock(mLoadMonitor->mLock);
|
||||
while (!mLoadMonitor->mShutdownPending) {
|
||||
mLoadInfo->UpdateSystemLoad();
|
||||
mLoadInfo->UpdateProcessLoad();
|
||||
float sysLoad = mLoadInfo->GetSystemLoad();
|
||||
float procLoad = mLoadInfo->GetProcessLoad();
|
||||
if ((++mLoadNoiseCounter % (LOG_MANY_ENABLED() ? 1 : 10)) == 0) {
|
||||
LOG(("System Load: %f Process Load: %f", sysLoad, procLoad));
|
||||
mLoadNoiseCounter = 0;
|
||||
}
|
||||
mLoadMonitor->SetSystemLoad(sysLoad);
|
||||
mLoadMonitor->SetProcessLoad(procLoad);
|
||||
|
||||
mLoadMonitor->mCondVar.Wait(PR_MillisecondsToInterval(kLoadUpdateInterval));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<LoadInfo> mLoadInfo;
|
||||
nsRefPtr<LoadMonitor> mLoadMonitor;
|
||||
int mLoadNoiseCounter;
|
||||
};
|
||||
|
||||
void
|
||||
LoadMonitor::SetProcessLoad(float load) {
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
mProcessLoad = load;
|
||||
}
|
||||
|
||||
void
|
||||
LoadMonitor::SetSystemLoad(float load) {
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
mSystemLoad = load;
|
||||
}
|
||||
|
||||
float
|
||||
LoadMonitor::GetProcessLoad() {
|
||||
MutexAutoLock lock(mLock);
|
||||
float load = mProcessLoad;
|
||||
return load;
|
||||
}
|
||||
|
||||
float
|
||||
LoadMonitor::GetSystemLoad() {
|
||||
MutexAutoLock lock(mLock);
|
||||
float load = mSystemLoad;
|
||||
return load;
|
||||
}
|
||||
|
||||
nsresult
|
||||
LoadMonitor::Init(nsRefPtr<LoadMonitor> &self)
|
||||
{
|
||||
if (!Preferences::GetBool("media.navigator.load_adapt", false)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
if (!gLoadMonitorLog)
|
||||
gLoadMonitorLog = PR_NewLogModule("LoadMonitor");
|
||||
LOG(("Initializing LoadMonitor"));
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID) || defined(LINUX)
|
||||
nsRefPtr<LoadMonitorAddObserver> addObsRunner = new LoadMonitorAddObserver(self);
|
||||
NS_DispatchToMainThread(addObsRunner, NS_DISPATCH_NORMAL);
|
||||
|
||||
NS_NewNamedThread("Sys Load Info", getter_AddRefs(mLoadInfoThread));
|
||||
|
||||
nsRefPtr<LoadInfoCollectRunner> runner = new LoadInfoCollectRunner(self);
|
||||
mLoadInfoThread->Dispatch(runner, NS_DISPATCH_NORMAL);
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
50
content/media/webrtc/LoadMonitor.h
Normal file
50
content/media/webrtc/LoadMonitor.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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 _LOADMONITOR_H_
|
||||
#define _LOADMONITOR_H_
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
class LoadInfoUpdateRunner;
|
||||
class LoadInfoCollectRunner;
|
||||
|
||||
class LoadMonitor MOZ_FINAL : public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
LoadMonitor();
|
||||
~LoadMonitor();
|
||||
|
||||
nsresult Init(nsRefPtr<LoadMonitor> &self);
|
||||
void Shutdown();
|
||||
float GetSystemLoad();
|
||||
float GetProcessLoad();
|
||||
|
||||
friend class LoadInfoCollectRunner;
|
||||
|
||||
private:
|
||||
|
||||
void SetProcessLoad(float load);
|
||||
void SetSystemLoad(float load);
|
||||
|
||||
mozilla::Mutex mLock;
|
||||
mozilla::CondVar mCondVar;
|
||||
bool mShutdownPending;
|
||||
nsCOMPtr<nsIThread> mLoadInfoThread;
|
||||
float mSystemLoad;
|
||||
float mProcessLoad;
|
||||
};
|
||||
|
||||
#endif /* _LOADMONITOR_H_ */
|
@ -55,6 +55,8 @@ MediaEngineWebRTC::MediaEngineWebRTC()
|
||||
if (compMgr) {
|
||||
compMgr->IsContractIDRegistered(NS_TABSOURCESERVICE_CONTRACTID, &mHasTabVideoSource);
|
||||
}
|
||||
mLoadMonitor = new LoadMonitor();
|
||||
mLoadMonitor->Init(mLoadMonitor);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -359,6 +361,8 @@ MediaEngineWebRTC::Shutdown()
|
||||
|
||||
mVideoEngine = nullptr;
|
||||
mVoiceEngine = nullptr;
|
||||
|
||||
mLoadMonitor->Shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "AudioSegment.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "LoadMonitor.h"
|
||||
|
||||
// WebRTC library includes follow
|
||||
|
||||
@ -356,6 +357,8 @@ public:
|
||||
, mHasTabVideoSource(false)
|
||||
{
|
||||
AsyncLatencyLogger::Get(true)->AddRef();
|
||||
mLoadMonitor = new LoadMonitor();
|
||||
mLoadMonitor->Init(mLoadMonitor);
|
||||
}
|
||||
#else
|
||||
MediaEngineWebRTC();
|
||||
@ -402,6 +405,8 @@ private:
|
||||
nsDOMCameraManager* mCameraManager;
|
||||
uint64_t mWindowId;
|
||||
#endif
|
||||
|
||||
nsRefPtr<LoadMonitor> mLoadMonitor;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -14,8 +14,9 @@ EXPORTS += [
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBRTC']:
|
||||
EXPORTS += ['MediaEngineWebRTC.h']
|
||||
EXPORTS += ['LoadMonitor.h', 'MediaEngineWebRTC.h']
|
||||
SOURCES += [
|
||||
'LoadMonitor.cpp',
|
||||
'MediaEngineTabVideoSource.cpp',
|
||||
'MediaEngineWebRTC.cpp',
|
||||
'MediaEngineWebRTCAudio.cpp',
|
||||
|
@ -3688,13 +3688,13 @@ nsGlobalWindow::GetContent(JSContext* aCx, ErrorResult& aError)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
JS::Rooted<JS::Value> val(aCx, JS::NullValue());
|
||||
aError = treeOwner->GetContentWindow(aCx, val.address());
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &val.toObject();
|
||||
return val.toObjectOrNull();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMWindow>
|
||||
|
@ -36,3 +36,4 @@ support-files =
|
||||
[test_window_indexing.html]
|
||||
[test_writable-replaceable.html]
|
||||
[test_urlExceptions.html]
|
||||
[test_openDialogChromeOnly.html]
|
||||
|
41
dom/base/test/test_openDialogChromeOnly.html
Normal file
41
dom/base/test/test_openDialogChromeOnly.html
Normal file
@ -0,0 +1,41 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=931768
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 931768</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 931768 **/
|
||||
|
||||
try {
|
||||
openDialog("chrome://browser/content/browser.xul");
|
||||
ok(false, "Calling openDialog from unprivileged script should throw.");
|
||||
} catch (e) {
|
||||
// FIXME e should be a ReferenceError once we switch Window to new WebIDL bindings
|
||||
ok(e.name == "SecurityError",
|
||||
"openDialog shouldn't be callable to unprivileged script.");
|
||||
todo(e instanceof ReferenceError,
|
||||
"openDialog shouldn't be available to unprivileged script.");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=931768">Mozilla Bug 931768</a>
|
||||
<p id="display">
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -3,6 +3,8 @@ support-files =
|
||||
DOMTestCase.js
|
||||
activity-home.css
|
||||
exclusions.js
|
||||
# Timeouts on OS X (bug 921635)
|
||||
skip-if = os == "mac"
|
||||
|
||||
[test_PIsetdatanomodificationallowederrEE.html]
|
||||
[test_attrcreatedocumentfragment.html]
|
||||
|
@ -2,6 +2,8 @@
|
||||
support-files =
|
||||
DOMTestCase.js
|
||||
exclusions.js
|
||||
# Timeouts on OS X (bug 921635)
|
||||
skip-if = os == "mac"
|
||||
|
||||
[test_attrgetownerelement01.html]
|
||||
[test_attrgetownerelement02.html]
|
||||
|
@ -1,5 +1,7 @@
|
||||
[DEFAULT]
|
||||
support-files = DOMTestCase.js
|
||||
# Timeouts on OS X (bug 921635)
|
||||
skip-if = os == "mac"
|
||||
|
||||
[test_HTMLAnchorElement01.html]
|
||||
[test_HTMLAnchorElement02.html]
|
||||
@ -16,28 +18,16 @@ support-files = DOMTestCase.js
|
||||
[test_HTMLAnchorElement13.html]
|
||||
[test_HTMLAnchorElement14.html]
|
||||
[test_HTMLAppletElement01.html]
|
||||
# This and the below - timeouts on OS X (bug 921635)
|
||||
skip-if = os == "mac"
|
||||
[test_HTMLAppletElement02.html]
|
||||
skip-if = os == "mac"
|
||||
[test_HTMLAppletElement03.html]
|
||||
skip-if = os == "mac"
|
||||
[test_HTMLAppletElement04.html]
|
||||
skip-if = os == "mac"
|
||||
[test_HTMLAppletElement05.html]
|
||||
skip-if = os == "mac"
|
||||
[test_HTMLAppletElement06.html]
|
||||
skip-if = os == "mac"
|
||||
[test_HTMLAppletElement07.html]
|
||||
skip-if = os == "mac"
|
||||
[test_HTMLAppletElement08.html]
|
||||
skip-if = os == "mac"
|
||||
[test_HTMLAppletElement09.html]
|
||||
skip-if = os == "mac"
|
||||
[test_HTMLAppletElement10.html]
|
||||
skip-if = os == "mac"
|
||||
[test_HTMLAppletElement11.html]
|
||||
skip-if = os == "mac"
|
||||
[test_HTMLAreaElement01.html]
|
||||
[test_HTMLAreaElement02.html]
|
||||
[test_HTMLAreaElement03.html]
|
||||
|
@ -327,12 +327,12 @@ partial interface Window {
|
||||
* arguments, plus any additional arguments are passed on as
|
||||
* arguments on the dialog's window object (window.arguments).
|
||||
*/
|
||||
[Throws] WindowProxy? openDialog(optional DOMString url = "",
|
||||
optional DOMString name = "",
|
||||
optional DOMString options = "",
|
||||
any... extraArguments);
|
||||
[Throws, ChromeOnly] WindowProxy? openDialog(optional DOMString url = "",
|
||||
optional DOMString name = "",
|
||||
optional DOMString options = "",
|
||||
any... extraArguments);
|
||||
|
||||
[Replaceable, Throws] readonly attribute object content;
|
||||
[Replaceable, Throws] readonly attribute object? content;
|
||||
};
|
||||
|
||||
Window implements TouchEventHandlers;
|
||||
|
@ -122,6 +122,12 @@ public:
|
||||
return resultMatrix;
|
||||
}
|
||||
|
||||
Matrix& operator*=(const Matrix &aMatrix)
|
||||
{
|
||||
Matrix resultMatrix = *this * aMatrix;
|
||||
return *this = resultMatrix;
|
||||
}
|
||||
|
||||
/* Returns true if the other matrix is fuzzy-equal to this matrix.
|
||||
* Note that this isn't a cheap comparison!
|
||||
*/
|
||||
@ -159,6 +165,13 @@ public:
|
||||
_31 == 0.0f && _32 == 0.0f;
|
||||
}
|
||||
|
||||
/* Returns true if the matrix is singular.
|
||||
*/
|
||||
bool IsSingular() const
|
||||
{
|
||||
return Determinant() == 0;
|
||||
}
|
||||
|
||||
GFX2D_API void NudgeToIntegers();
|
||||
|
||||
private:
|
||||
|
@ -445,9 +445,7 @@ ClientLayerManager::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
|
||||
|
||||
// This is derived from the code in
|
||||
// gfx/layers/ipc/CompositorParent.cpp::TransformShadowTree.
|
||||
const gfx3DMatrix& rootTransform = GetRoot()->GetTransform();
|
||||
CSSToLayerScale paintScale = metrics.mDevPixelsPerCSSPixel
|
||||
/ LayerToLayoutDeviceScale(rootTransform.GetXScale(), rootTransform.GetYScale());
|
||||
CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel();
|
||||
const CSSRect& metricsDisplayPort =
|
||||
(aDrawingCritical && !metrics.mCriticalDisplayPort.IsEmpty()) ?
|
||||
metrics.mCriticalDisplayPort : metrics.mDisplayPort;
|
||||
|
@ -484,14 +484,8 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram
|
||||
&treeTransform,
|
||||
scrollOffset);
|
||||
|
||||
const gfx3DMatrix& rootTransform = mLayerManager->GetRoot()->GetTransform();
|
||||
const FrameMetrics& metrics = container->GetFrameMetrics();
|
||||
// XXX We use rootTransform instead of metrics.mResolution here because on
|
||||
// Fennec the resolution is set on the root layer rather than the scrollable layer.
|
||||
// The SyncFrameMetrics call and the paintScale variable are used on Fennec only
|
||||
// so it doesn't affect any other platforms. See bug 732971.
|
||||
CSSToLayerScale paintScale = metrics.mDevPixelsPerCSSPixel
|
||||
/ LayerToLayoutDeviceScale(rootTransform.GetXScale(), rootTransform.GetYScale());
|
||||
CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel();
|
||||
CSSRect displayPort(metrics.mCriticalDisplayPort.IsEmpty() ?
|
||||
metrics.mDisplayPort : metrics.mCriticalDisplayPort);
|
||||
LayerMargin fixedLayerMargins(0, 0, 0, 0);
|
||||
@ -522,15 +516,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram
|
||||
|
||||
// Apply resolution scaling to the old transform - the layer tree as it is
|
||||
// doesn't have the necessary transform to display correctly.
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// XXX We use rootTransform instead of the resolution on the individual layer's
|
||||
// FrameMetrics on Fennec because the resolution is set on the root layer rather
|
||||
// than the scrollable layer. See bug 732971. On non-Fennec we do the right thing.
|
||||
LayoutDeviceToLayerScale resolution(1.0 / rootTransform.GetXScale(),
|
||||
1.0 / rootTransform.GetYScale());
|
||||
#else
|
||||
LayoutDeviceToLayerScale resolution = metrics.mCumulativeResolution;
|
||||
#endif
|
||||
oldTransform.Scale(resolution.scale, resolution.scale, 1);
|
||||
|
||||
AlignFixedAndStickyLayers(aLayer, aLayer, oldTransform, fixedLayerMargins);
|
||||
@ -542,7 +528,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const LayoutDeviceToLayerScale& aResolution)
|
||||
AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
|
||||
{
|
||||
LayerComposite* layerComposite = aLayer->AsLayerComposite();
|
||||
ContainerLayer* container = aLayer->AsContainerLayer();
|
||||
@ -555,7 +541,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const LayoutDev
|
||||
|
||||
gfx3DMatrix treeTransform;
|
||||
|
||||
CSSToLayerScale geckoZoom = metrics.mDevPixelsPerCSSPixel * aResolution;
|
||||
CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel();
|
||||
|
||||
LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.mScrollOffset * geckoZoom);
|
||||
|
||||
@ -606,9 +592,9 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const LayoutDev
|
||||
// transformation we need to apply.
|
||||
LayerToScreenScale zoomAdjust = userZoom / geckoZoom;
|
||||
|
||||
LayerIntPoint geckoScroll(0, 0);
|
||||
LayerPoint geckoScroll(0, 0);
|
||||
if (metrics.IsScrollable()) {
|
||||
geckoScroll = scrollOffsetLayerPixels;
|
||||
geckoScroll = metrics.mScrollOffset * geckoZoom;
|
||||
}
|
||||
|
||||
LayerPoint translation = (userScroll / zoomAdjust) - geckoScroll;
|
||||
@ -633,7 +619,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const LayoutDev
|
||||
|
||||
// Apply resolution scaling to the old transform - the layer tree as it is
|
||||
// doesn't have the necessary transform to display correctly.
|
||||
oldTransform.Scale(aResolution.scale, aResolution.scale, 1);
|
||||
oldTransform.Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1);
|
||||
|
||||
// Make sure that overscroll and under-zoom are represented in the old
|
||||
// transform so that fixed position content moves and scales accordingly.
|
||||
@ -706,18 +692,7 @@ AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame)
|
||||
|
||||
for (uint32_t i = 0; i < scrollableLayers.Length(); i++) {
|
||||
if (scrollableLayers[i]) {
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// XXX We use rootTransform instead of the resolution on the individual layer's
|
||||
// FrameMetrics on Fennec because the resolution is set on the root layer rather
|
||||
// than the scrollable layer. See bug 732971. On non-Fennec we do the right thing.
|
||||
const gfx3DMatrix& rootTransform = root->GetTransform();
|
||||
LayoutDeviceToLayerScale resolution(1.0 / rootTransform.GetXScale(),
|
||||
1.0 / rootTransform.GetYScale());
|
||||
#else
|
||||
LayoutDeviceToLayerScale resolution =
|
||||
scrollableLayers[i]->AsContainerLayer()->GetFrameMetrics().mCumulativeResolution;
|
||||
#endif
|
||||
TransformScrollableLayer(scrollableLayers[i], resolution);
|
||||
TransformScrollableLayer(scrollableLayers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ public:
|
||||
bool IsFirstPaint() { return mIsFirstPaint; }
|
||||
|
||||
private:
|
||||
void TransformScrollableLayer(Layer* aLayer, const LayoutDeviceToLayerScale& aResolution);
|
||||
void TransformScrollableLayer(Layer* aLayer);
|
||||
// Return true if an AsyncPanZoomController content transform was
|
||||
// applied for |aLayer|. *aWantNextFrame is set to true if the
|
||||
// controller wants another animation frame.
|
||||
|
@ -541,14 +541,10 @@ LayerManagerComposite::ComputeRenderIntegrity()
|
||||
Layer* primaryScrollable = GetPrimaryScrollableLayer();
|
||||
if (primaryScrollable) {
|
||||
// This is derived from the code in
|
||||
// gfx/layers/ipc/CompositorParent.cpp::TransformShadowTree.
|
||||
const gfx3DMatrix& rootTransform = root->GetTransform();
|
||||
float devPixelRatioX = 1 / rootTransform.GetXScale();
|
||||
float devPixelRatioY = 1 / rootTransform.GetYScale();
|
||||
|
||||
gfx3DMatrix transform = primaryScrollable->GetEffectiveTransform();
|
||||
transform.ScalePost(devPixelRatioX, devPixelRatioY, 1);
|
||||
// AsyncCompositionManager::TransformScrollableLayer
|
||||
const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
|
||||
gfx3DMatrix transform = primaryScrollable->GetEffectiveTransform();
|
||||
transform.ScalePost(metrics.mResolution.scale, metrics.mResolution.scale, 1);
|
||||
|
||||
// Clip the screen rect to the document bounds
|
||||
gfxRect documentBounds =
|
||||
|
@ -264,15 +264,10 @@ ThebesLayerComposite::GetCompositionBounds()
|
||||
parentMetrics.mCompositionBounds.width,
|
||||
parentMetrics.mCompositionBounds.height);
|
||||
|
||||
// Calculate the scale transform applied to the root layer to determine
|
||||
// the content resolution.
|
||||
Layer* rootLayer = Manager()->GetRoot();
|
||||
const gfx3DMatrix& rootTransform = rootLayer->GetTransform();
|
||||
LayerToCSSScale scale(rootTransform.GetXScale(),
|
||||
rootTransform.GetYScale());
|
||||
const FrameMetrics& metrics = scrollableLayer->GetFrameMetrics();
|
||||
LayerToCSSScale scale(1 / metrics.mResolution.scale);
|
||||
|
||||
// Get the content document bounds, in screen-space.
|
||||
const FrameMetrics& metrics = scrollableLayer->GetFrameMetrics();
|
||||
const LayerIntRect content = RoundedToInt(metrics.mScrollableRect / scale);
|
||||
// !!! WTF. this code is just wrong. See bug 881451.
|
||||
gfx::Point scrollOffset =
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <sys/types.h> // for int32_t
|
||||
#include "gfxContext.h" // for gfxContext
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/UserData.h" // for UserData, UserDataKey
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsBoundingMetrics.h" // for nsBoundingMetrics
|
||||
@ -37,6 +38,7 @@ class nsRenderingContext
|
||||
{
|
||||
typedef mozilla::gfx::UserData UserData;
|
||||
typedef mozilla::gfx::UserDataKey UserDataKey;
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
|
||||
public:
|
||||
nsRenderingContext() : mP2A(0.) {}
|
||||
@ -49,6 +51,7 @@ public:
|
||||
|
||||
// These accessors will never return null.
|
||||
gfxContext *ThebesContext() { return mThebes; }
|
||||
DrawTarget *GetDrawTarget() { return mThebes->GetDrawTarget(); }
|
||||
nsDeviceContext *DeviceContext() { return mDeviceContext; }
|
||||
int32_t AppUnitsPerDevPixel() { return NSToIntRound(mP2A); }
|
||||
|
||||
|
19
gfx/tests/crashtests/836225-1.html
Normal file
19
gfx/tests/crashtests/836225-1.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
@font-face {
|
||||
font-family: foo;
|
||||
src: url(PigLatin_Plane15.ttf);
|
||||
}
|
||||
body {
|
||||
font-family: foo;
|
||||
font-size: 24px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
󰁐󰁩󰁧 󰁌󰁡󰁴󰁩󰁮
|
||||
</body>
|
||||
</html>
|
BIN
gfx/tests/crashtests/PigLatin_Plane15.ttf
Normal file
BIN
gfx/tests/crashtests/PigLatin_Plane15.ttf
Normal file
Binary file not shown.
@ -97,5 +97,6 @@ load 783041-3.html
|
||||
load 783041-4.html
|
||||
asserts-if(gtk2Widget,1) load 798853.html # bug 868792
|
||||
asserts-if(winWidget,0-1) skip-if(B2G) load 815489.html
|
||||
load 836225-1.html
|
||||
load 839745-1.html
|
||||
load 856784-1.html
|
||||
|
@ -1455,6 +1455,9 @@ gfxFontCache::gfxFontCache()
|
||||
obs->AddObserver(new Observer, "memory-pressure", false);
|
||||
}
|
||||
|
||||
#ifndef RELEASE_BUILD
|
||||
// Currently disabled for release builds, due to unexplained crashes
|
||||
// during expiration; see bug 717175 & 894798.
|
||||
mWordCacheExpirationTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (mWordCacheExpirationTimer) {
|
||||
mWordCacheExpirationTimer->
|
||||
@ -1462,6 +1465,7 @@ gfxFontCache::gfxFontCache()
|
||||
SHAPED_WORD_TIMEOUT_SECONDS * 1000,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
gfxFontCache::~gfxFontCache()
|
||||
|
@ -156,7 +156,7 @@ gfxPattern::GetPattern(DrawTarget *aTarget, Matrix *aPatternTransform)
|
||||
|
||||
if (!mPattern) {
|
||||
mGfxPattern = new (mSurfacePattern.addr())
|
||||
SurfacePattern(mSourceSurface, EXTEND_CLAMP, mTransform);
|
||||
SurfacePattern(mSourceSurface, ToExtendMode(mExtend), mTransform);
|
||||
return mGfxPattern;
|
||||
}
|
||||
|
||||
|
@ -3664,6 +3664,8 @@ class MRandom : public MNullaryInstruction
|
||||
bool possiblyCalls() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void computeRange();
|
||||
};
|
||||
|
||||
class MMathFunction
|
||||
@ -3751,6 +3753,7 @@ class MMathFunction
|
||||
|| function_ == ASin || function_ == ACos || function_ == Floor;
|
||||
}
|
||||
void trySpecializeFloat32();
|
||||
void computeRange();
|
||||
};
|
||||
|
||||
class MAdd : public MBinaryArithInstruction
|
||||
@ -5258,6 +5261,7 @@ class MBoundsCheck
|
||||
virtual AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
void computeRange();
|
||||
};
|
||||
|
||||
// Bailout if index < minimum.
|
||||
@ -5615,6 +5619,7 @@ class MArrayPush
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
|
||||
}
|
||||
void computeRange();
|
||||
};
|
||||
|
||||
// Array.prototype.concat on two dense arrays.
|
||||
|
@ -1365,6 +1365,55 @@ MArgumentsLength::computeRange()
|
||||
setRange(Range::NewUInt32Range(0, SNAPSHOT_MAX_NARGS));
|
||||
}
|
||||
|
||||
void
|
||||
MBoundsCheck::computeRange()
|
||||
{
|
||||
// Just transfer the incoming index range to the output. The length() is
|
||||
// also interesting, but it is handled as a bailout check, and we're
|
||||
// computing a pre-bailout range here.
|
||||
setRange(new Range(index()));
|
||||
}
|
||||
|
||||
void
|
||||
MArrayPush::computeRange()
|
||||
{
|
||||
// MArrayPush returns the new array length.
|
||||
setRange(Range::NewUInt32Range(0, UINT32_MAX));
|
||||
}
|
||||
|
||||
void
|
||||
MMathFunction::computeRange()
|
||||
{
|
||||
Range opRange(getOperand(0));
|
||||
switch (function()) {
|
||||
case Sin:
|
||||
case Cos:
|
||||
if (!opRange.canBeInfiniteOrNaN())
|
||||
setRange(Range::NewDoubleRange(-1.0, 1.0));
|
||||
break;
|
||||
case Sign:
|
||||
if (!opRange.canBeNaN()) {
|
||||
// Note that Math.sign(-0) is -0, and we treat -0 as equal to 0.
|
||||
int32_t lower = -1;
|
||||
int32_t upper = 1;
|
||||
if (opRange.hasInt32LowerBound() && opRange.lower() >= 0)
|
||||
lower = 0;
|
||||
if (opRange.hasInt32UpperBound() && opRange.upper() <= 0)
|
||||
upper = 0;
|
||||
setRange(Range::NewInt32Range(lower, upper));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MRandom::computeRange()
|
||||
{
|
||||
setRange(Range::NewDoubleRange(0.0, 1.0));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Range Analysis
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -67,6 +67,9 @@ class LUnbox : public LInstructionHelper<1, 2, 0>
|
||||
const LAllocation *type() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const char *extraName() const {
|
||||
return StringFromMIRType(mir()->type());
|
||||
}
|
||||
};
|
||||
|
||||
class LUnboxFloatingPoint : public LInstructionHelper<1, 2, 0>
|
||||
|
@ -55,6 +55,10 @@ class LUnbox : public LUnboxBase {
|
||||
LUnbox(const LAllocation &input)
|
||||
: LUnboxBase(input)
|
||||
{ }
|
||||
|
||||
const char *extraName() const {
|
||||
return StringFromMIRType(mir()->type());
|
||||
}
|
||||
};
|
||||
|
||||
class LUnboxFloatingPoint : public LUnboxBase {
|
||||
|
@ -68,6 +68,9 @@ class LUnbox : public LInstructionHelper<1, 2, 0>
|
||||
const LAllocation *type() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const char *extraName() const {
|
||||
return StringFromMIRType(mir()->type());
|
||||
}
|
||||
};
|
||||
|
||||
class LUnboxFloatingPoint : public LInstructionHelper<1, 2, 0>
|
||||
|
@ -4417,25 +4417,6 @@ JS::CanCompileOffThread(JSContext *cx, const CompileOptions &options)
|
||||
if (cx->runtime()->activeGCInAtomsZone())
|
||||
return false;
|
||||
|
||||
// Blacklist filenames which cause mysterious assertion failures in
|
||||
// graphics code on OS X. These seem to tickle some preexisting race
|
||||
// condition unrelated to off thread compilation. See bug 897655.
|
||||
static const char *blacklist[] = {
|
||||
#ifdef XP_MACOSX
|
||||
"chrome://browser/content/places/editBookmarkOverlay.js",
|
||||
"chrome://browser/content/nsContextMenu.js",
|
||||
"chrome://browser/content/newtab/newTab.js",
|
||||
"chrome://browser/content/places/browserPlacesViews.js",
|
||||
#endif
|
||||
nullptr
|
||||
};
|
||||
|
||||
const char *filename = options.filename;
|
||||
for (const char **ptest = blacklist; *ptest; ptest++) {
|
||||
if (!strcmp(*ptest, filename))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
|
@ -43,6 +43,7 @@ DECLARE_DISPLAY_ITEM_TYPE(PLUGIN_VIDEO)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(PRINT_PLUGIN)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(REMOTE)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(REMOTE_SHADOW)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(RESOLUTION)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SCROLL_LAYER)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SCROLL_INFO_LAYER)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SELECTION_OVERLAY)
|
||||
|
@ -3308,6 +3308,35 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
nsDisplayResolution::nsDisplayResolution(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsDisplayList* aList,
|
||||
uint32_t aFlags)
|
||||
: nsDisplayOwnLayer(aBuilder, aFrame, aList, aFlags) {
|
||||
MOZ_COUNT_CTOR(nsDisplayResolution);
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
nsDisplayResolution::~nsDisplayResolution() {
|
||||
MOZ_COUNT_DTOR(nsDisplayResolution);
|
||||
}
|
||||
#endif
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayResolution::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) {
|
||||
nsIPresShell* presShell = mFrame->PresContext()->PresShell();
|
||||
nsDisplayItem::ContainerParameters containerParameters(
|
||||
presShell->GetXResolution(), presShell->GetYResolution(), nsIntPoint(),
|
||||
aContainerParameters);
|
||||
|
||||
nsRefPtr<Layer> layer = nsDisplayOwnLayer::BuildLayer(
|
||||
aBuilder, aManager, containerParameters);
|
||||
layer->SetPostScale(1.0f / presShell->GetXResolution(),
|
||||
1.0f / presShell->GetYResolution());
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
nsDisplayFixedPosition::nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame,
|
||||
nsIFrame* aFixedPosFrame,
|
||||
|
@ -2610,6 +2610,25 @@ private:
|
||||
uint32_t mFlags;
|
||||
};
|
||||
|
||||
/**
|
||||
* A display item for subdocuments to capture the resolution from the presShell
|
||||
* and ensure that it gets applied to all the right elements. This item creates
|
||||
* a container layer.
|
||||
*/
|
||||
class nsDisplayResolution : public nsDisplayOwnLayer {
|
||||
public:
|
||||
nsDisplayResolution(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
nsDisplayList* aList, uint32_t aFlags);
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayResolution();
|
||||
#endif
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) MOZ_OVERRIDE;
|
||||
NS_DISPLAY_DECL_NAME("Resolution", TYPE_RESOLUTION)
|
||||
};
|
||||
|
||||
/**
|
||||
* A display item used to represent fixed position elements. This will ensure
|
||||
* the contents gets its own layer, and that the built layer will have
|
||||
|
@ -372,8 +372,10 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
|
||||
nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable();
|
||||
bool constructResolutionItem = subdocRootFrame &&
|
||||
(presShell->GetXResolution() != 1.0 || presShell->GetYResolution() != 1.0);
|
||||
bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD;
|
||||
bool needsOwnLayer = constructZoomItem ||
|
||||
bool needsOwnLayer = constructResolutionItem || constructZoomItem ||
|
||||
presContext->IsRootContentDocument() || (sf && sf->IsScrollingActive());
|
||||
|
||||
nsDisplayList childItems;
|
||||
@ -423,13 +425,25 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a resolution and/or zoom item if needed. If one or both of those is
|
||||
// created, we don't need to create a separate nsDisplayOwnLayer.
|
||||
|
||||
if (constructResolutionItem) {
|
||||
nsDisplayResolution* resolutionItem =
|
||||
new (aBuilder) nsDisplayResolution(aBuilder, subdocRootFrame, &childItems,
|
||||
nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS);
|
||||
childItems.AppendToTop(resolutionItem);
|
||||
needsOwnLayer = false;
|
||||
}
|
||||
if (constructZoomItem) {
|
||||
nsDisplayZoom* zoomItem =
|
||||
new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems,
|
||||
subdocAPD, parentAPD,
|
||||
nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS);
|
||||
childItems.AppendToTop(zoomItem);
|
||||
} else if (needsOwnLayer) {
|
||||
needsOwnLayer = false;
|
||||
}
|
||||
if (needsOwnLayer) {
|
||||
// We always want top level content documents to be in their own layer.
|
||||
nsDisplayOwnLayer* layerItem = new (aBuilder) nsDisplayOwnLayer(
|
||||
aBuilder, subdocRootFrame ? subdocRootFrame : this,
|
||||
|
@ -41,7 +41,6 @@ MOCHITEST_FILES = \
|
||||
test_bug424627.html \
|
||||
test_bug438840.html \
|
||||
test_bug448860.html \
|
||||
test_bug448987.html \
|
||||
file_bug448987.html \
|
||||
file_bug448987_ref.html \
|
||||
file_bug448987_notref.html \
|
||||
@ -108,6 +107,9 @@ MOCHITEST_FILES = \
|
||||
$(srcdir)/../../base/tests/enableTestPlugin.js \
|
||||
$(NULL)
|
||||
|
||||
# Disabled for being too sensitive to timing changes (bug 932296)
|
||||
# test_bug448987.html \
|
||||
|
||||
# Disable the caret movement by word test on Linux because the shortcut keys
|
||||
# are defined in system level. So, it depends on the environment.
|
||||
ifndef MOZ_WIDGET_GTK
|
||||
|
@ -25,15 +25,15 @@ endif
|
||||
|
||||
ifdef MOZ_VORBIS
|
||||
SHARED_LIBRARY_LIBS += \
|
||||
$(DEPTH)/media/libvorbis/lib/$(LIB_PREFIX)vorbis.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/media/libogg/src/$(LIB_PREFIX)ogg.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/media/libvorbis/$(LIB_PREFIX)vorbis.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/media/libogg/$(LIB_PREFIX)ogg.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifdef MOZ_TREMOR
|
||||
SHARED_LIBRARY_LIBS += \
|
||||
$(DEPTH)/media/libtremor/lib/$(LIB_PREFIX)tremor.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/media/libogg/src/$(LIB_PREFIX)ogg.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/media/libogg/$(LIB_PREFIX)ogg.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
@ -8,7 +8,7 @@ fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azur
|
||||
== continuation-positioned-inline-1.html continuation-positioned-inline-ref.html
|
||||
== continuation-positioned-inline-2.html continuation-positioned-inline-ref.html
|
||||
== scrollframe-1.html scrollframe-1-ref.html
|
||||
skip-if(B2G) fuzzy-if(Android,9,39) == scrollframe-2.html scrollframe-2-ref.html #bug 756530
|
||||
skip-if(B2G) fuzzy-if(Android,9,185) == scrollframe-2.html scrollframe-2-ref.html #bug 756530
|
||||
fuzzy-if(gtk2Widget,1,8) == select-1.html select-1-ref.html
|
||||
fuzzy-if(gtk2Widget,1,8) == select-1-dynamic.html select-1-ref.html
|
||||
== select-2.html select-2-ref.html
|
||||
|
@ -300,7 +300,7 @@ skip-if(B2G) == 273681-1.html 273681-1-ref.html
|
||||
== 283686-2.html 283686-2-ref.html
|
||||
== 283686-3.html about:blank
|
||||
== 289384-1.xhtml 289384-ref.xhtml
|
||||
random-if(d2d) fuzzy-if(Android&&AndroidVersion>=15,8,200) HTTP == 289480.html#top 289480-ref.html # basically-verbatim acid2 test, HTTP for a 404 page -- bug 578114 for the d2d failures
|
||||
random-if(d2d) fuzzy-if(Android&&AndroidVersion>=15,8,1439) HTTP == 289480.html#top 289480-ref.html # basically-verbatim acid2 test, HTTP for a 404 page -- bug 578114 for the d2d failures
|
||||
== 290129-1.html 290129-1-ref.html
|
||||
skip-if(B2G) == 291078-1.html 291078-1-ref.html
|
||||
== 291078-2.html 291078-2-ref.html
|
||||
|
@ -1,6 +1,6 @@
|
||||
== 166591-dynamic-1.html 166591-dynamic-1-ref.html
|
||||
fuzzy-if(Android&&AndroidVersion>=15,8,50) == 336736-1a.html 336736-1-ref.html
|
||||
== 336736-1b.html 336736-1-ref.html
|
||||
fuzzy-if(Android&&AndroidVersion>=15,8,50) == 336736-1b.html 336736-1-ref.html
|
||||
== 406073-1.html 406073-1-ref.html
|
||||
== 407016-2.html 407016-2-ref.html
|
||||
fuzzy-if(Android&&AndroidVersion>=15,8,220) == 413027-4.html 413027-4-ref.html
|
||||
|
@ -48,4 +48,4 @@ fails == column-contain-1a.html column-contain-1-ref.html
|
||||
== column-contain-1b.html column-contain-1-ref.html
|
||||
== block-in-inline-1.html block-in-inline-1-ref.html
|
||||
fuzzy-if(Android,8,1533) == block-in-inline-2.html block-in-inline-2-ref.html
|
||||
fuzzy-if(Android,8,306) fuzzy-if(OSX==10.8,1,11) == block-in-inline-3.html block-in-inline-3-ref.html
|
||||
fuzzy-if(Android,8,630) fuzzy-if(OSX==10.8,1,11) == block-in-inline-3.html block-in-inline-3-ref.html
|
||||
|
@ -22,8 +22,8 @@ fails-if(Android) == rotatex-perspective-3a.html rotatex-perspective-3-ref.html
|
||||
skip-if(B2G) == preserve3d-4a.html green-rect.html
|
||||
fuzzy-if(Android&&AndroidVersion>=15,4,300) == preserve3d-5a.html preserve3d-5-ref.html
|
||||
== scale3d-z.html scalez-1-ref.html
|
||||
fuzzy-if(winWidget,102,580) fuzzy-if(d2d,143,681) fails-if(Android&&AndroidVersion<15) fuzzy-if(OSX==10.8,145,752) == scale3d-all.html scale3d-1-ref.html # subpixel AA
|
||||
fuzzy-if(winWidget,102,580) fuzzy-if(d2d,143,681) fails-if(Android&&AndroidVersion<15) fuzzy-if(OSX==10.8,145,752) == scale3d-all-separate.html scale3d-1-ref.html # subpixel AA
|
||||
fuzzy-if(winWidget,102,580) fuzzy-if(d2d,143,681) fails-if(Android) fuzzy-if(OSX==10.8,145,752) == scale3d-all.html scale3d-1-ref.html # subpixel AA
|
||||
fuzzy-if(winWidget,102,580) fuzzy-if(d2d,143,681) fails-if(Android) fuzzy-if(OSX==10.8,145,752) == scale3d-all-separate.html scale3d-1-ref.html # subpixel AA
|
||||
== scale3d-xz.html scale3d-1-ref.html
|
||||
== translatez-1a.html translatez-1-ref.html
|
||||
!= translatez-1b.html translatez-1-ref.html
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
// 290770). See bug 290852 for foreignObject complications.
|
||||
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint)=0;
|
||||
|
||||
// Get bounds in our gfxContext's coordinates space (in app units)
|
||||
// Get bounds in our nsSVGOuterSVGFrame's coordinates space (in app units)
|
||||
NS_IMETHOD_(nsRect) GetCoveredRegion()=0;
|
||||
|
||||
// Called on SVG child frames (except NS_FRAME_IS_NONDISPLAY frames)
|
||||
|
@ -7,10 +7,12 @@
|
||||
#include "nsSVGPatternFrame.h"
|
||||
|
||||
// Keep others in (case-insensitive) order:
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfxPattern.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsISVGChildFrame.h"
|
||||
@ -26,6 +28,7 @@
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Helper classes
|
||||
@ -140,6 +143,23 @@ nsSVGPatternFrame::GetCanvasTM(uint32_t aFor, nsIFrame* aTransformRoot)
|
||||
// Helper functions
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Calculate the maximum expansion of a matrix */
|
||||
static float
|
||||
MaxExpansion(const Matrix &aMatrix)
|
||||
{
|
||||
// maximum expansion derivation from
|
||||
// http://lists.cairographics.org/archives/cairo/2004-October/001980.html
|
||||
// and also implemented in cairo_matrix_transformed_circle_major_axis
|
||||
double a = aMatrix._11;
|
||||
double b = aMatrix._12;
|
||||
double c = aMatrix._21;
|
||||
double d = aMatrix._22;
|
||||
double f = (a * a + b * b + c * c + d * d) / 2;
|
||||
double g = (a * a + b * b - c * c - d * d) / 2;
|
||||
double h = a * c + b * d;
|
||||
return sqrt(f + sqrt(g * g + h * h));
|
||||
}
|
||||
|
||||
// The SVG specification says that the 'patternContentUnits' attribute "has no effect if
|
||||
// attribute ‘viewBox’ is specified". We still need to include a bbox scale
|
||||
// if the viewBox is specified and _patternUnits_ is set to or defaults to
|
||||
@ -161,7 +181,7 @@ GetPatternMatrix(uint16_t aPatternUnits,
|
||||
const gfxMatrix &patternTransform,
|
||||
const gfxRect &bbox,
|
||||
const gfxRect &callerBBox,
|
||||
const gfxMatrix &callerCTM)
|
||||
const Matrix &callerCTM)
|
||||
{
|
||||
// We really want the pattern matrix to handle translations
|
||||
gfxFloat minx = bbox.X();
|
||||
@ -172,7 +192,7 @@ GetPatternMatrix(uint16_t aPatternUnits,
|
||||
miny += callerBBox.Y();
|
||||
}
|
||||
|
||||
float scale = 1.0f / nsSVGUtils::MaxExpansion(callerCTM);
|
||||
float scale = 1.0f / MaxExpansion(callerCTM);
|
||||
gfxMatrix patternMatrix = patternTransform;
|
||||
patternMatrix.Scale(scale, scale);
|
||||
patternMatrix.Translate(gfxPoint(minx, miny));
|
||||
@ -186,7 +206,7 @@ GetTargetGeometry(gfxRect *aBBox,
|
||||
uint16_t aPatternContentUnits,
|
||||
uint16_t aPatternUnits,
|
||||
nsIFrame *aTarget,
|
||||
const gfxMatrix &aContextMatrix,
|
||||
const Matrix &aContextMatrix,
|
||||
const gfxRect *aOverrideBounds)
|
||||
{
|
||||
*aBBox = aOverrideBounds ? *aOverrideBounds : nsSVGUtils::GetBBox(aTarget);
|
||||
@ -199,7 +219,7 @@ GetTargetGeometry(gfxRect *aBBox,
|
||||
|
||||
// OK, now fix up the bounding box to reflect user coordinates
|
||||
// We handle device unit scaling in pattern matrix
|
||||
float scale = nsSVGUtils::MaxExpansion(aContextMatrix);
|
||||
float scale = MaxExpansion(aContextMatrix);
|
||||
if (scale <= 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -267,14 +287,14 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
|
||||
viewBox,
|
||||
patternContentUnits, patternUnits,
|
||||
aSource,
|
||||
aContextMatrix,
|
||||
ToMatrix(aContextMatrix),
|
||||
aOverrideBounds)))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Construct the CTM that we will provide to our children when we
|
||||
// render them into the tile.
|
||||
gfxMatrix ctm = ConstructCTM(viewBox, patternContentUnits, patternUnits,
|
||||
callerBBox, aContextMatrix, aSource);
|
||||
callerBBox, ToMatrix(aContextMatrix), aSource);
|
||||
if (ctm.IsSingular()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -291,7 +311,7 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
|
||||
// Get the bounding box of the pattern. This will be used to determine
|
||||
// the size of the surface, and will also be used to define the bounding
|
||||
// box for the pattern tile.
|
||||
gfxRect bbox = GetPatternRect(patternUnits, callerBBox, aContextMatrix, aSource);
|
||||
gfxRect bbox = GetPatternRect(patternUnits, callerBBox, ToMatrix(aContextMatrix), aSource);
|
||||
|
||||
// Get the pattern transform
|
||||
gfxMatrix patternTransform = GetPatternTransform();
|
||||
@ -304,7 +324,7 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
|
||||
// Get the transformation matrix that we will hand to the renderer's pattern
|
||||
// routine.
|
||||
*patternMatrix = GetPatternMatrix(patternUnits, patternTransform,
|
||||
bbox, callerBBox, aContextMatrix);
|
||||
bbox, callerBBox, ToMatrix(aContextMatrix));
|
||||
if (patternMatrix->IsSingular()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -574,7 +594,7 @@ nsSVGPatternFrame::GetReferencedPatternIfNotInUse()
|
||||
gfxRect
|
||||
nsSVGPatternFrame::GetPatternRect(uint16_t aPatternUnits,
|
||||
const gfxRect &aTargetBBox,
|
||||
const gfxMatrix &aTargetCTM,
|
||||
const Matrix &aTargetCTM,
|
||||
nsIFrame *aTarget)
|
||||
{
|
||||
// We need to initialize our box
|
||||
@ -593,7 +613,7 @@ nsSVGPatternFrame::GetPatternRect(uint16_t aPatternUnits,
|
||||
width = nsSVGUtils::ObjectSpace(aTargetBBox, tmpWidth);
|
||||
height = nsSVGUtils::ObjectSpace(aTargetBBox, tmpHeight);
|
||||
} else {
|
||||
float scale = nsSVGUtils::MaxExpansion(aTargetCTM);
|
||||
float scale = MaxExpansion(aTargetCTM);
|
||||
x = nsSVGUtils::UserSpace(aTarget, tmpX) * scale;
|
||||
y = nsSVGUtils::UserSpace(aTarget, tmpY) * scale;
|
||||
width = nsSVGUtils::UserSpace(aTarget, tmpWidth) * scale;
|
||||
@ -608,7 +628,7 @@ nsSVGPatternFrame::ConstructCTM(const nsSVGViewBox& aViewBox,
|
||||
uint16_t aPatternContentUnits,
|
||||
uint16_t aPatternUnits,
|
||||
const gfxRect &callerBBox,
|
||||
const gfxMatrix &callerCTM,
|
||||
const Matrix &callerCTM,
|
||||
nsIFrame *aTarget)
|
||||
{
|
||||
gfxMatrix tCTM;
|
||||
@ -622,7 +642,7 @@ nsSVGPatternFrame::ConstructCTM(const nsSVGViewBox& aViewBox,
|
||||
if (targetContent->IsSVG()) {
|
||||
ctx = static_cast<nsSVGElement*>(targetContent)->GetCtx();
|
||||
}
|
||||
float scale = nsSVGUtils::MaxExpansion(callerCTM);
|
||||
float scale = MaxExpansion(callerCTM);
|
||||
tCTM.Scale(scale, scale);
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "nsSVGPaintServerFrame.h"
|
||||
|
||||
class gfxASurface;
|
||||
@ -30,6 +31,8 @@ typedef nsSVGPaintServerFrame nsSVGPatternFrameBase;
|
||||
*/
|
||||
class nsSVGPatternFrame : public nsSVGPatternFrameBase
|
||||
{
|
||||
typedef mozilla::gfx::Matrix Matrix;
|
||||
|
||||
public:
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
@ -117,13 +120,13 @@ protected:
|
||||
nsIFrame* GetPatternFirstChild();
|
||||
gfxRect GetPatternRect(uint16_t aPatternUnits,
|
||||
const gfxRect &bbox,
|
||||
const gfxMatrix &callerCTM,
|
||||
const Matrix &callerCTM,
|
||||
nsIFrame *aTarget);
|
||||
gfxMatrix ConstructCTM(const nsSVGViewBox& aViewBox,
|
||||
uint16_t aPatternContentUnits,
|
||||
uint16_t aPatternUnits,
|
||||
const gfxRect &callerBBox,
|
||||
const gfxMatrix &callerCTM,
|
||||
const Matrix &callerCTM,
|
||||
nsIFrame *aTarget);
|
||||
|
||||
private:
|
||||
|
@ -1295,22 +1295,6 @@ nsSVGUtils::CanOptimizeOpacity(nsIFrame *aFrame)
|
||||
return false;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGUtils::MaxExpansion(const gfxMatrix &aMatrix)
|
||||
{
|
||||
// maximum expansion derivation from
|
||||
// http://lists.cairographics.org/archives/cairo/2004-October/001980.html
|
||||
// and also implemented in cairo_matrix_transformed_circle_major_axis
|
||||
double a = aMatrix.xx;
|
||||
double b = aMatrix.yx;
|
||||
double c = aMatrix.xy;
|
||||
double d = aMatrix.yy;
|
||||
double f = (a * a + b * b + c * c + d * d) / 2;
|
||||
double g = (a * a + b * b - c * c - d * d) / 2;
|
||||
double h = a * c + b * d;
|
||||
return sqrt(f + sqrt(g * g + h * h));
|
||||
}
|
||||
|
||||
gfxMatrix
|
||||
nsSVGUtils::AdjustMatrixForUnits(const gfxMatrix &aMatrix,
|
||||
nsSVGEnum *aUnits,
|
||||
|
@ -507,10 +507,6 @@ public:
|
||||
static bool
|
||||
CanOptimizeOpacity(nsIFrame *aFrame);
|
||||
|
||||
/* Calculate the maximum expansion of a matrix */
|
||||
static float
|
||||
MaxExpansion(const gfxMatrix &aMatrix);
|
||||
|
||||
/**
|
||||
* Take the CTM to userspace for an element, and adjust it to a CTM to its
|
||||
* object bounding box space if aUnits is SVG_UNIT_TYPE_OBJECTBOUNDINGBOX.
|
||||
|
@ -1,7 +1,7 @@
|
||||
The source from this directory was copied from the libogg subversion
|
||||
repository using the update.sh script. The only changes made were
|
||||
those applied by update.sh and the addition/upate of Makefile.in files
|
||||
for the Mozilla build system.
|
||||
those applied by update.sh and the addition/update of moz.build and
|
||||
Makefile.in files for the Mozilla build system.
|
||||
|
||||
The svn revision number used was r17287.
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
DIRS += ['ogg']
|
||||
|
||||
MODULE = 'ogg'
|
||||
|
@ -1,12 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
EXPORTS.ogg += [
|
||||
'config_types.h',
|
||||
'ogg.h',
|
||||
'os_types.h',
|
||||
]
|
||||
|
@ -4,7 +4,24 @@
|
||||
# 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/.
|
||||
|
||||
DIRS += ['include', 'src']
|
||||
|
||||
MODULE = 'ogg'
|
||||
|
||||
EXPORTS.ogg += [
|
||||
'include/ogg/config_types.h',
|
||||
'include/ogg/ogg.h',
|
||||
'include/ogg/os_types.h',
|
||||
]
|
||||
|
||||
LIBRARY_NAME = 'ogg'
|
||||
|
||||
SOURCES += [
|
||||
'src/ogg_bitwise.c',
|
||||
'src/ogg_framing.c',
|
||||
]
|
||||
|
||||
MSVC_ENABLE_PGO = True
|
||||
|
||||
FORCE_STATIC_LIB = True
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||
NO_VISIBILITY_FLAGS = True
|
||||
|
@ -1,4 +0,0 @@
|
||||
# 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/.
|
||||
|
@ -1,14 +0,0 @@
|
||||
diff -r f33a75da59bd media/libvorbis/lib/os.h
|
||||
--- a/media/libvorbis/lib/os.h Sun Dec 07 19:31:40 2008 -0800
|
||||
+++ b/media/libvorbis/lib/os.h Mon Dec 15 16:26:36 2008 +0800
|
||||
@@ -25,6 +25,10 @@
|
||||
#include <ogg/os_types.h>
|
||||
|
||||
#include "misc.h"
|
||||
+
|
||||
+#ifdef SOLARIS
|
||||
+#define HAVE_ALLOCA_H
|
||||
+#endif
|
||||
|
||||
#ifndef _V_IFDEFJAIL_H_
|
||||
# define _V_IFDEFJAIL_H_
|
@ -1,10 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
DIRS += ['vorbis']
|
||||
|
||||
MODULE = 'vorbis'
|
||||
|
@ -1,10 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
EXPORTS.vorbis += [
|
||||
'codec.h',
|
||||
]
|
||||
|
@ -1,8 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
|
||||
ifeq ($(OS_ARCH),AIX)
|
||||
DEFINES += -Dalloca=__alloca
|
||||
endif
|
@ -1,39 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
MODULE = 'vorbis'
|
||||
|
||||
LIBRARY_NAME = 'vorbis'
|
||||
|
||||
SOURCES += [
|
||||
'vorbis_analysis.c',
|
||||
'vorbis_bitrate.c',
|
||||
'vorbis_block.c',
|
||||
'vorbis_codebook.c',
|
||||
'vorbis_envelope.c',
|
||||
'vorbis_floor0.c',
|
||||
'vorbis_floor1.c',
|
||||
'vorbis_info.c',
|
||||
'vorbis_lookup.c',
|
||||
'vorbis_lpc.c',
|
||||
'vorbis_lsp.c',
|
||||
'vorbis_mapping0.c',
|
||||
'vorbis_mdct.c',
|
||||
'vorbis_psy.c',
|
||||
'vorbis_registry.c',
|
||||
'vorbis_res0.c',
|
||||
'vorbis_sharedbook.c',
|
||||
'vorbis_smallft.c',
|
||||
'vorbis_synthesis.c',
|
||||
'vorbis_window.c',
|
||||
]
|
||||
|
||||
MSVC_ENABLE_PGO = True
|
||||
|
||||
FORCE_STATIC_LIB = True
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||
NO_VISIBILITY_FLAGS = True
|
@ -4,7 +4,46 @@
|
||||
# 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/.
|
||||
|
||||
DIRS += ['include', 'lib']
|
||||
|
||||
MODULE = 'vorbis'
|
||||
|
||||
EXPORTS.vorbis += [
|
||||
'include/vorbis/codec.h',
|
||||
]
|
||||
|
||||
LIBRARY_NAME = 'vorbis'
|
||||
|
||||
SOURCES += [
|
||||
'lib/vorbis_analysis.c',
|
||||
'lib/vorbis_bitrate.c',
|
||||
'lib/vorbis_block.c',
|
||||
'lib/vorbis_codebook.c',
|
||||
'lib/vorbis_envelope.c',
|
||||
'lib/vorbis_floor0.c',
|
||||
'lib/vorbis_floor1.c',
|
||||
'lib/vorbis_info.c',
|
||||
'lib/vorbis_lookup.c',
|
||||
'lib/vorbis_lpc.c',
|
||||
'lib/vorbis_lsp.c',
|
||||
'lib/vorbis_mapping0.c',
|
||||
'lib/vorbis_mdct.c',
|
||||
'lib/vorbis_psy.c',
|
||||
'lib/vorbis_registry.c',
|
||||
'lib/vorbis_res0.c',
|
||||
'lib/vorbis_sharedbook.c',
|
||||
'lib/vorbis_smallft.c',
|
||||
'lib/vorbis_synthesis.c',
|
||||
'lib/vorbis_window.c',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'AIX':
|
||||
DEFINES['alloca'] = '__alloca'
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'SunOS':
|
||||
DEFINES['HAVE_ALLOCA_H'] = True
|
||||
|
||||
MSVC_ENABLE_PGO = True
|
||||
|
||||
FORCE_STATIC_LIB = True
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||
NO_VISIBILITY_FLAGS = True
|
||||
|
@ -47,4 +47,4 @@ cp $1/COPYING ./COPYING
|
||||
cp $1/README ./README
|
||||
cp $1/AUTHORS ./AUTHORS
|
||||
|
||||
patch -p3 < ./alloca.diff
|
||||
# Add any patches against upstream here.
|
||||
|
@ -15,6 +15,7 @@ EXPORTS.mtransport += [
|
||||
'../runnable_utils.h',
|
||||
'../runnable_utils_generated.h',
|
||||
'../sigslot.h',
|
||||
'../simpletokenbucket.h',
|
||||
'../transportflow.h',
|
||||
'../transportlayer.h',
|
||||
'../transportlayerdtls.h',
|
||||
|
@ -13,6 +13,7 @@ mtransport_lcppsrcs = [
|
||||
'nriceresolver.cpp',
|
||||
'nriceresolverfake.cpp',
|
||||
'nrinterfaceprioritizer.cpp',
|
||||
'simpletokenbucket.cpp',
|
||||
'transportflow.cpp',
|
||||
'transportlayer.cpp',
|
||||
'transportlayerdtls.cpp',
|
||||
|
62
media/mtransport/simpletokenbucket.cpp
Normal file
62
media/mtransport/simpletokenbucket.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=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/. */
|
||||
|
||||
/* Original author: bcampen@mozilla.com */
|
||||
|
||||
#include "simpletokenbucket.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "prinrval.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
SimpleTokenBucket::SimpleTokenBucket(size_t bucket_size,
|
||||
size_t tokens_per_second) :
|
||||
max_tokens_(bucket_size),
|
||||
num_tokens_(bucket_size),
|
||||
tokens_per_second_(tokens_per_second),
|
||||
last_time_tokens_added_(PR_IntervalNow()) {
|
||||
}
|
||||
|
||||
size_t SimpleTokenBucket::getTokens(size_t num_requested_tokens) {
|
||||
// Only fill if there isn't enough to satisfy the request.
|
||||
// If we get tokens so seldomly that we are able to roll the timer all
|
||||
// the way around its range, then we lose that entire range of time
|
||||
// for token accumulation. Probably not the end of the world.
|
||||
if (num_requested_tokens > num_tokens_) {
|
||||
PRIntervalTime now = PR_IntervalNow();
|
||||
|
||||
// If we roll over the max, since everything in this calculation is the same
|
||||
// unsigned type, this will still yield the elapsed time (unless we've
|
||||
// wrapped more than once).
|
||||
PRIntervalTime elapsed_ticks = now - last_time_tokens_added_;
|
||||
|
||||
uint32_t elapsed_milli_sec = PR_IntervalToMilliseconds(elapsed_ticks);
|
||||
size_t tokens_to_add = (elapsed_milli_sec * tokens_per_second_)/1000;
|
||||
|
||||
// Only update our timestamp if we added some tokens
|
||||
// TODO:(bcampen@mozilla.com) Should we attempt to "save" leftover time?
|
||||
if (tokens_to_add) {
|
||||
num_tokens_ += tokens_to_add;
|
||||
if (num_tokens_ > max_tokens_) {
|
||||
num_tokens_ = max_tokens_;
|
||||
}
|
||||
|
||||
last_time_tokens_added_ = now;
|
||||
}
|
||||
|
||||
if (num_requested_tokens > num_tokens_) {
|
||||
return num_tokens_;
|
||||
}
|
||||
}
|
||||
|
||||
num_tokens_ -= num_requested_tokens;
|
||||
return num_requested_tokens;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
54
media/mtransport/simpletokenbucket.h
Normal file
54
media/mtransport/simpletokenbucket.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=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/. */
|
||||
|
||||
/* Original author: bcampen@mozilla.com */
|
||||
|
||||
/*
|
||||
* This file defines a dirt-simple token bucket class.
|
||||
*/
|
||||
|
||||
#ifndef simpletokenbucket_h__
|
||||
#define simpletokenbucket_h__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "prinrval.h"
|
||||
|
||||
#include "m_cpp_utils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class SimpleTokenBucket {
|
||||
public:
|
||||
/*
|
||||
* Create a SimpleTokenBucket with a given maximum size and
|
||||
* token replenishment rate.
|
||||
* (eg; if you want a maximum rate of 5 per second over a 7 second
|
||||
* period, call SimpleTokenBucket b(5*7, 5);)
|
||||
*/
|
||||
SimpleTokenBucket(size_t bucket_size, size_t tokens_per_second);
|
||||
|
||||
/*
|
||||
* Attempt to acquire a number of tokens. If successful, returns
|
||||
* |num_tokens|, otherwise returns the number of tokens currently
|
||||
* in the bucket.
|
||||
* Note: To get the number of tokens in the bucket, pass something
|
||||
* like UINT32_MAX.
|
||||
*/
|
||||
size_t getTokens(size_t num_tokens);
|
||||
|
||||
protected: // Allow testing to touch these.
|
||||
uint64_t max_tokens_;
|
||||
uint64_t num_tokens_;
|
||||
size_t tokens_per_second_;
|
||||
PRIntervalTime last_time_tokens_added_;
|
||||
|
||||
DISALLOW_COPY_ASSIGN(SimpleTokenBucket);
|
||||
};
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // simpletokenbucket_h__
|
||||
|
@ -11,6 +11,7 @@ if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
|
||||
'ice_unittest.cpp',
|
||||
'nrappkit_unittest.cpp',
|
||||
'runnable_utils_unittest.cpp',
|
||||
'simpletokenbucket_unittest.cpp',
|
||||
'sockettransportservice_unittest.cpp',
|
||||
'TestSyncRunnable.cpp',
|
||||
'transport_unittests.cpp',
|
||||
|
115
media/mtransport/test/simpletokenbucket_unittest.cpp
Normal file
115
media/mtransport/test/simpletokenbucket_unittest.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=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/. */
|
||||
|
||||
/* Original author: bcampen@mozilla.com */
|
||||
|
||||
#include "simpletokenbucket.h"
|
||||
|
||||
#define GTEST_HAS_RTTI 0
|
||||
#include "gtest/gtest.h"
|
||||
#include "gtest_utils.h"
|
||||
|
||||
using mozilla::SimpleTokenBucket;
|
||||
|
||||
class TestSimpleTokenBucket : public SimpleTokenBucket {
|
||||
public:
|
||||
TestSimpleTokenBucket(size_t bucketSize, size_t tokensPerSecond) :
|
||||
SimpleTokenBucket(bucketSize, tokensPerSecond) {
|
||||
}
|
||||
|
||||
void fastForward(int32_t timeMilliSeconds) {
|
||||
if (timeMilliSeconds >= 0) {
|
||||
last_time_tokens_added_ -= PR_MillisecondsToInterval(timeMilliSeconds);
|
||||
} else {
|
||||
last_time_tokens_added_ += PR_MillisecondsToInterval(-timeMilliSeconds);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST(SimpleTokenBucketTest, TestConstruct) {
|
||||
TestSimpleTokenBucket b(10, 1);
|
||||
}
|
||||
|
||||
TEST(SimpleTokenBucketTest, TestGet) {
|
||||
TestSimpleTokenBucket b(10, 1);
|
||||
ASSERT_EQ(5U, b.getTokens(5));
|
||||
}
|
||||
|
||||
TEST(SimpleTokenBucketTest, TestGetAll) {
|
||||
TestSimpleTokenBucket b(10, 1);
|
||||
ASSERT_EQ(10U, b.getTokens(10));
|
||||
}
|
||||
|
||||
TEST(SimpleTokenBucketTest, TestGetInsufficient) {
|
||||
TestSimpleTokenBucket b(10, 1);
|
||||
ASSERT_EQ(5U, b.getTokens(5));
|
||||
ASSERT_EQ(5U, b.getTokens(6));
|
||||
}
|
||||
|
||||
TEST(SimpleTokenBucketTest, TestGetBucketCount) {
|
||||
TestSimpleTokenBucket b(10, 1);
|
||||
ASSERT_EQ(10U, b.getTokens(UINT32_MAX));
|
||||
ASSERT_EQ(5U, b.getTokens(5));
|
||||
ASSERT_EQ(5U, b.getTokens(UINT32_MAX));
|
||||
}
|
||||
|
||||
TEST(SimpleTokenBucketTest, TestTokenRefill) {
|
||||
TestSimpleTokenBucket b(10, 1);
|
||||
ASSERT_EQ(5U, b.getTokens(5));
|
||||
b.fastForward(1000);
|
||||
ASSERT_EQ(6U, b.getTokens(6));
|
||||
}
|
||||
|
||||
TEST(SimpleTokenBucketTest, TestNoTimeWasted) {
|
||||
// Makes sure that when the time elapsed is insufficient to add any
|
||||
// tokens to the bucket, the internal timestamp that is used in this
|
||||
// calculation is not updated (ie; two subsequent 0.5 second elapsed times
|
||||
// counts as a full second)
|
||||
TestSimpleTokenBucket b(10, 1);
|
||||
ASSERT_EQ(5U, b.getTokens(5));
|
||||
b.fastForward(500);
|
||||
ASSERT_EQ(5U, b.getTokens(6));
|
||||
b.fastForward(500);
|
||||
ASSERT_EQ(6U, b.getTokens(6));
|
||||
}
|
||||
|
||||
TEST(SimpleTokenBucketTest, TestNegativeTime) {
|
||||
TestSimpleTokenBucket b(10, 1);
|
||||
b.fastForward(-1000);
|
||||
// Make sure we don't end up with an invalid number of tokens, but otherwise
|
||||
// permit anything.
|
||||
ASSERT_GT(11U, b.getTokens(100));
|
||||
}
|
||||
|
||||
TEST(SimpleTokenBucketTest, TestEmptyBucket) {
|
||||
TestSimpleTokenBucket b(10, 1);
|
||||
ASSERT_EQ(10U, b.getTokens(10));
|
||||
ASSERT_EQ(0U, b.getTokens(10));
|
||||
}
|
||||
|
||||
TEST(SimpleTokenBucketTest, TestEmptyThenFillBucket) {
|
||||
TestSimpleTokenBucket b(10, 1);
|
||||
ASSERT_EQ(10U, b.getTokens(10));
|
||||
ASSERT_EQ(0U, b.getTokens(1));
|
||||
b.fastForward(50000);
|
||||
ASSERT_EQ(10U, b.getTokens(10));
|
||||
}
|
||||
|
||||
TEST(SimpleTokenBucketTest, TestNoOverflow) {
|
||||
TestSimpleTokenBucket b(10, 1);
|
||||
ASSERT_EQ(10U, b.getTokens(10));
|
||||
ASSERT_EQ(0U, b.getTokens(1));
|
||||
b.fastForward(50000);
|
||||
ASSERT_EQ(10U, b.getTokens(11));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
int rv = RUN_ALL_TESTS();
|
||||
return rv;
|
||||
}
|
||||
|
@ -470,7 +470,7 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
|
||||
// Always abort updates if the resolution has changed. There's no use
|
||||
// in drawing at the incorrect resolution.
|
||||
if (!FloatUtils.fuzzyEquals(resolution, viewportMetrics.zoomFactor)) {
|
||||
Log.d(LOGTAG, "Aborting draw due to resolution change");
|
||||
Log.d(LOGTAG, "Aborting draw due to resolution change: " + resolution + " != " + viewportMetrics.zoomFactor);
|
||||
mProgressiveUpdateData.abort = true;
|
||||
return mProgressiveUpdateData;
|
||||
}
|
||||
|
@ -2,11 +2,13 @@
|
||||
package @ANDROID_PACKAGE_NAME@.tests;
|
||||
|
||||
import @ANDROID_PACKAGE_NAME@.*;
|
||||
import com.jayway.android.robotium.solo.Condition;
|
||||
import com.jayway.android.robotium.solo.Solo;
|
||||
import android.widget.ListView;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import java.util.ArrayList;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
import java.util.ArrayList;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@ -17,7 +19,8 @@ import org.json.JSONObject;
|
||||
* and that the reading list is properly populated after adding or removing reader items
|
||||
*/
|
||||
public class testReaderMode extends AboutHomeTest {
|
||||
int height,width;
|
||||
static final int EVENT_CLEAR_DELAY_MS = 3000;
|
||||
static final int READER_ICON_MAX_WAIT_MS = 15000;
|
||||
|
||||
@Override
|
||||
protected int getTestType() {
|
||||
@ -33,26 +36,27 @@ public class testReaderMode extends AboutHomeTest {
|
||||
Actions.RepeatedEventExpecter paintExpecter;
|
||||
ListView list;
|
||||
View child;
|
||||
View readerIcon;
|
||||
String textUrl = getAbsoluteUrl(StringHelper.ROBOCOP_TEXT_PAGE_URL);
|
||||
String devType = mDevice.type;
|
||||
int childNo;
|
||||
int eventClearDelay = 3000;
|
||||
int height;
|
||||
int width;
|
||||
|
||||
contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
|
||||
loadAndPaint(textUrl);
|
||||
contentEventExpecter.blockForEvent();
|
||||
contentEventExpecter.unregisterListener();
|
||||
|
||||
// Add the page to the Reading List using log click on the reader icon
|
||||
// Add the page to the Reading List using long click on the reader icon
|
||||
readerIcon = getReaderIcon();
|
||||
contentReaderAddedExpecter = mActions.expectGeckoEvent("Reader:Added");
|
||||
mSolo.clickLongOnView(getReaderIcon());
|
||||
mSolo.clickLongOnView(readerIcon);
|
||||
String eventData = contentReaderAddedExpecter.blockForEventData();
|
||||
isAdded(eventData);
|
||||
contentReaderAddedExpecter.unregisterListener();
|
||||
|
||||
// Try to add the page to the Reading List using log click on the reader icon a second time
|
||||
// Try to add the page to the Reading List using long click on the reader icon a second time
|
||||
readerIcon = getReaderIcon();
|
||||
contentReaderAddedExpecter = mActions.expectGeckoEvent("Reader:Added");
|
||||
mSolo.clickLongOnView(getReaderIcon());
|
||||
mSolo.clickLongOnView(readerIcon);
|
||||
eventData = contentReaderAddedExpecter.blockForEventData();
|
||||
isAdded(eventData);
|
||||
contentReaderAddedExpecter.unregisterListener();
|
||||
@ -60,8 +64,9 @@ public class testReaderMode extends AboutHomeTest {
|
||||
// Waiting for the favicon since is the last element loaded usually
|
||||
faviconExpecter = mActions.expectGeckoEvent("Reader:FaviconRequest");
|
||||
contentPageShowExpecter = mActions.expectGeckoEvent("Content:PageShow");
|
||||
readerIcon = getReaderIcon();
|
||||
paintExpecter = mActions.expectPaint();
|
||||
mSolo.clickOnView(getReaderIcon());
|
||||
mSolo.clickOnView(readerIcon);
|
||||
|
||||
// Changing devices orientation to be sure that all devices are in portrait when will access the reader toolbar
|
||||
mSolo.setActivityOrientation(Solo.PORTRAIT);
|
||||
@ -69,7 +74,7 @@ public class testReaderMode extends AboutHomeTest {
|
||||
faviconExpecter.unregisterListener();
|
||||
contentPageShowExpecter.blockForEvent();
|
||||
contentPageShowExpecter.unregisterListener();
|
||||
paintExpecter.blockUntilClear(eventClearDelay);
|
||||
paintExpecter.blockUntilClear(EVENT_CLEAR_DELAY_MS);
|
||||
paintExpecter.unregisterListener();
|
||||
verifyPageTitle("Robocop Text Page");
|
||||
|
||||
@ -150,10 +155,27 @@ public class testReaderMode extends AboutHomeTest {
|
||||
// Get the reader icon method
|
||||
protected View getReaderIcon() {
|
||||
View pageActionLayout = mSolo.getView(0x7f070025);
|
||||
ArrayList<String> pageActionLayoutChilds = new ArrayList();
|
||||
View actionLayoutItem = pageActionLayout;
|
||||
ViewGroup actionLayoutEntry = (ViewGroup)actionLayoutItem;
|
||||
final ViewGroup actionLayoutEntry = (ViewGroup)pageActionLayout;
|
||||
View icon = actionLayoutEntry.getChildAt(1);
|
||||
if (icon == null || icon.getVisibility() != View.VISIBLE) {
|
||||
// wait for the view to be visible, otherwise it may not respond
|
||||
// to clicks -- see bug 927578
|
||||
mAsserter.dumpLog("reader icon not visible -- waiting for visibility");
|
||||
Condition visibilityCondition = new Condition() {
|
||||
@Override
|
||||
public boolean isSatisfied() {
|
||||
View conditionIcon = actionLayoutEntry.getChildAt(1);
|
||||
if (conditionIcon == null ||
|
||||
conditionIcon.getVisibility() != View.VISIBLE)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
waitForCondition(visibilityCondition, READER_ICON_MAX_WAIT_MS);
|
||||
icon = actionLayoutEntry.getChildAt(1);
|
||||
mAsserter.ok(icon != null, "checking reader icon view", "reader icon view not null");
|
||||
mAsserter.ok(icon.getVisibility() == View.VISIBLE, "checking reader icon visible", "reader icon visible");
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
|
@ -2911,7 +2911,7 @@ Tab.prototype = {
|
||||
// we should never be drawing background tabs at resolutions other than the user-
|
||||
// visible zoom. for foreground tabs, however, if we are drawing at some other
|
||||
// resolution, we need to set the resolution as specified.
|
||||
let cwu = window.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
let cwu = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
if (BrowserApp.selectedTab == this) {
|
||||
if (resolution != this._drawZoom) {
|
||||
this._drawZoom = resolution;
|
||||
@ -2930,8 +2930,6 @@ Tab.prototype = {
|
||||
let geckoScrollY = this.browser.contentWindow.scrollY;
|
||||
aDisplayPort = this._dirtiestHackEverToWorkAroundGeckoRounding(aDisplayPort, geckoScrollX, geckoScrollY);
|
||||
|
||||
cwu = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
||||
let displayPort = {
|
||||
x: (aDisplayPort.left / resolution) - geckoScrollX,
|
||||
y: (aDisplayPort.top / resolution) - geckoScrollY,
|
||||
@ -3193,7 +3191,7 @@ Tab.prototype = {
|
||||
if (aForce || !fuzzyEquals(aZoom, this._zoom)) {
|
||||
this._zoom = aZoom;
|
||||
if (BrowserApp.selectedTab == this) {
|
||||
let cwu = window.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
let cwu = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
this._drawZoom = aZoom;
|
||||
cwu.setResolution(aZoom / window.devicePixelRatio, aZoom / window.devicePixelRatio);
|
||||
}
|
||||
|
@ -232,6 +232,7 @@ pref("media.navigator.video.default_fps",30);
|
||||
pref("media.navigator.video.default_minfps",10);
|
||||
pref("media.navigator.video.max_fs", 0); // unrestricted
|
||||
pref("media.navigator.video.max_fr", 0); // unrestricted
|
||||
pref("media.navigator.load_adapt", false);
|
||||
pref("media.peerconnection.enabled", true);
|
||||
pref("media.navigator.permission.disabled", false);
|
||||
pref("media.peerconnection.default_iceservers", "[{\"url\": \"stun:stun.services.mozilla.com\"}]");
|
||||
|
@ -65,6 +65,7 @@ nsGtkIMModule* nsGtkIMModule::sLastFocusedModule = nullptr;
|
||||
nsGtkIMModule::nsGtkIMModule(nsWindow* aOwnerWindow) :
|
||||
mOwnerWindow(aOwnerWindow), mLastFocusedWindow(nullptr),
|
||||
mContext(nullptr),
|
||||
mSimpleContext(nullptr),
|
||||
mDummyContext(nullptr),
|
||||
mCompositionStart(UINT32_MAX), mProcessingKeyEvent(nullptr),
|
||||
mCompositionState(eCompositionState_NotComposing),
|
||||
@ -114,6 +115,28 @@ nsGtkIMModule::Init()
|
||||
G_CALLBACK(nsGtkIMModule::OnEndCompositionCallback),
|
||||
this);
|
||||
|
||||
// Simple context
|
||||
mSimpleContext = gtk_im_context_simple_new();
|
||||
gtk_im_context_set_client_window(mSimpleContext, gdkWindow);
|
||||
g_signal_connect(mSimpleContext, "preedit_changed",
|
||||
G_CALLBACK(&nsGtkIMModule::OnChangeCompositionCallback),
|
||||
this);
|
||||
g_signal_connect(mSimpleContext, "retrieve_surrounding",
|
||||
G_CALLBACK(&nsGtkIMModule::OnRetrieveSurroundingCallback),
|
||||
this);
|
||||
g_signal_connect(mSimpleContext, "delete_surrounding",
|
||||
G_CALLBACK(&nsGtkIMModule::OnDeleteSurroundingCallback),
|
||||
this);
|
||||
g_signal_connect(mSimpleContext, "commit",
|
||||
G_CALLBACK(&nsGtkIMModule::OnCommitCompositionCallback),
|
||||
this);
|
||||
g_signal_connect(mSimpleContext, "preedit_start",
|
||||
G_CALLBACK(nsGtkIMModule::OnStartCompositionCallback),
|
||||
this);
|
||||
g_signal_connect(mSimpleContext, "preedit_end",
|
||||
G_CALLBACK(nsGtkIMModule::OnEndCompositionCallback),
|
||||
this);
|
||||
|
||||
// Dummy context
|
||||
mDummyContext = gtk_im_multicontext_new();
|
||||
gtk_im_context_set_client_window(mDummyContext, gdkWindow);
|
||||
@ -168,6 +191,12 @@ nsGtkIMModule::OnDestroyWindow(nsWindow* aWindow)
|
||||
mContext = nullptr;
|
||||
}
|
||||
|
||||
if (mSimpleContext) {
|
||||
gtk_im_context_set_client_window(mSimpleContext, nullptr);
|
||||
g_object_unref(mSimpleContext);
|
||||
mSimpleContext = nullptr;
|
||||
}
|
||||
|
||||
if (mDummyContext) {
|
||||
// mContext and mDummyContext have the same slaveType and signal_data
|
||||
// so no need for another workaround_gtk_im_display_closed.
|
||||
@ -548,7 +577,9 @@ nsGtkIMModule::GetContext()
|
||||
if (IsEnabled()) {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
if (mInputContext.mIMEState.mEnabled == IMEState::PASSWORD) {
|
||||
return mSimpleContext;
|
||||
}
|
||||
return mDummyContext;
|
||||
}
|
||||
|
||||
@ -556,7 +587,6 @@ bool
|
||||
nsGtkIMModule::IsEnabled()
|
||||
{
|
||||
return mInputContext.mIMEState.mEnabled == IMEState::ENABLED ||
|
||||
mInputContext.mIMEState.mEnabled == IMEState::PASSWORD ||
|
||||
mInputContext.mIMEState.mEnabled == IMEState::PLUGIN;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user