mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Merge last green changeset of mozilla-inbound to mozilla-central
This commit is contained in:
commit
d89ef2f8f8
2
.gitignore
vendored
2
.gitignore
vendored
@ -23,7 +23,7 @@ ID
|
||||
security/manager/.nss.checkout
|
||||
|
||||
# Build directories
|
||||
obj/*
|
||||
obj*/
|
||||
|
||||
# Build directories for js shell
|
||||
*/_DBG.OBJ/
|
||||
|
@ -32,7 +32,7 @@
|
||||
<![CDATA[
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Hack to make xul:tabbrowser work
|
||||
// Hacks to make xul:tabbrowser work
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const CC = Components.classes;
|
||||
@ -53,6 +53,8 @@
|
||||
|
||||
var gFindBarInitialized = false;
|
||||
|
||||
function goSetCommandEnabled() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Tests
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -60,8 +62,8 @@ XPCOMUtils.defineLazyGetter(Services, 'fm', function() {
|
||||
|
||||
// In order to use http:// scheme instead of file:// scheme
|
||||
// (that is much more restricted) the following code kick-off
|
||||
// a local http server listening on http://127.0.0.1:8888 and
|
||||
// http://localhost:8888.
|
||||
// a local http server listening on http://127.0.0.1:7777 and
|
||||
// http://localhost:7777.
|
||||
function startupHttpd(baseDir, port) {
|
||||
const httpdURL = 'chrome://browser/content/httpd.js';
|
||||
let httpd = {};
|
||||
@ -91,6 +93,9 @@ function addPermissions(urls) {
|
||||
|
||||
|
||||
var shell = {
|
||||
// FIXME/bug 678695: this should be a system setting
|
||||
preferredScreenBrightness: 1.0,
|
||||
|
||||
get home() {
|
||||
delete this.home;
|
||||
return this.home = document.getElementById('homescreen');
|
||||
@ -139,7 +144,7 @@ var shell = {
|
||||
baseDir.pop();
|
||||
baseDir = baseDir.join('/');
|
||||
|
||||
const SERVER_PORT = 8888;
|
||||
const SERVER_PORT = 6666;
|
||||
startupHttpd(baseDir, SERVER_PORT);
|
||||
|
||||
let baseHost = 'http://localhost';
|
||||
@ -195,7 +200,7 @@ var shell = {
|
||||
this.sendEvent(this.home.contentWindow, 'home');
|
||||
break;
|
||||
case evt.DOM_VK_SLEEP:
|
||||
screen.mozEnabled = !screen.mozEnabled;
|
||||
this.toggleScreen();
|
||||
break;
|
||||
case evt.DOM_VK_ESCAPE:
|
||||
if (evt.defaultPrevented)
|
||||
@ -206,6 +211,7 @@ var shell = {
|
||||
break;
|
||||
case 'load':
|
||||
this.home.removeEventListener('load', this, true);
|
||||
this.turnScreenOn();
|
||||
this.sendEvent(window, 'ContentStart');
|
||||
break;
|
||||
case 'MozApplicationManifest':
|
||||
@ -248,7 +254,21 @@ var shell = {
|
||||
let event = content.document.createEvent('CustomEvent');
|
||||
event.initCustomEvent(type, true, true, details ? details : {});
|
||||
content.dispatchEvent(event);
|
||||
}
|
||||
},
|
||||
toggleScreen: function shell_toggleScreen() {
|
||||
if (screen.mozEnabled)
|
||||
this.turnScreenOff();
|
||||
else
|
||||
this.turnScreenOn();
|
||||
},
|
||||
turnScreenOff: function shell_turnScreenOff() {
|
||||
screen.mozEnabled = false;
|
||||
screen.mozBrightness = 0.0;
|
||||
},
|
||||
turnScreenOn: function shell_turnScreenOn() {
|
||||
screen.mozEnabled = true;
|
||||
screen.mozBrightness = this.preferredScreenBrightness;
|
||||
},
|
||||
};
|
||||
|
||||
(function VirtualKeyboardManager() {
|
||||
|
@ -40,6 +40,7 @@
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
id="shell"
|
||||
width="480" height="800"
|
||||
windowtype="navigator:browser"
|
||||
#ifdef ANDROID
|
||||
sizemode="fullscreen"
|
||||
#endif
|
||||
|
@ -1,12 +1,12 @@
|
||||
pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/");
|
||||
pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/");
|
||||
// The time interval between checks for a new version (in seconds)
|
||||
pref("app.update.interval", 7200); // 2 hours
|
||||
pref("app.update.interval", 3600); // 1 hour
|
||||
// The time interval between the downloading of mar file chunks in the
|
||||
// background (in seconds)
|
||||
pref("app.update.download.backgroundInterval", 60);
|
||||
// Give the user x seconds to react before showing the big UI. default=12 hours
|
||||
pref("app.update.promptWaitTime", 43200);
|
||||
// Give the user x seconds to react before showing the big UI. default=1 hour
|
||||
pref("app.update.promptWaitTime", 3600);
|
||||
// URL user can browse to manually if for some reason all update installation
|
||||
// attempts fail.
|
||||
pref("app.update.url.manual", "http://nightly.mozilla.org/");
|
||||
|
@ -42,8 +42,13 @@
|
||||
* to remove all traces of visiting a site.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function run_test() {
|
||||
PRIVATEBROWSING_CONTRACT_ID = "@mozilla.org/privatebrowsing-wrapper;1";
|
||||
load("do_test_removeDataFromDomain.js");
|
||||
do_test();
|
||||
|
||||
// Shutdown the download manager.
|
||||
Services.obs.notifyObservers(null, "quit-application", null);
|
||||
}
|
||||
|
@ -42,8 +42,13 @@
|
||||
* to remove all traces of visiting a site.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function run_test() {
|
||||
PRIVATEBROWSING_CONTRACT_ID = "@mozilla.org/privatebrowsing;1";
|
||||
load("do_test_removeDataFromDomain_activeDownloads.js");
|
||||
do_test();
|
||||
|
||||
// Shutdown the download manager.
|
||||
Services.obs.notifyObservers(null, "quit-application", null);
|
||||
}
|
||||
|
@ -42,8 +42,13 @@
|
||||
* to remove all traces of visiting a site.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function run_test() {
|
||||
PRIVATEBROWSING_CONTRACT_ID = "@mozilla.org/privatebrowsing;1";
|
||||
load("do_test_removeDataFromDomain.js");
|
||||
do_test();
|
||||
|
||||
// Shutdown the download manager.
|
||||
Services.obs.notifyObservers(null, "quit-application", null);
|
||||
}
|
||||
|
@ -42,8 +42,13 @@
|
||||
* to remove all traces of visiting a site.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function run_test() {
|
||||
PRIVATEBROWSING_CONTRACT_ID = "@mozilla.org/privatebrowsing;1";
|
||||
load("do_test_removeDataFromDomain_activeDownloads.js");
|
||||
do_test();
|
||||
|
||||
// Shutdown the download manager.
|
||||
Services.obs.notifyObservers(null, "quit-application", null);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
#navigator-toolbox > toolbar:not(:-moz-lwtheme),
|
||||
#browser-bottombox:not(:-moz-lwtheme) {
|
||||
background-color: @customToolbarColor@;
|
||||
@ -82,7 +82,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-compositor) {
|
||||
@media (-moz-windows-compositor) {
|
||||
/* These should be hidden w/ glass enabled. Windows draws its own buttons. */
|
||||
.titlebar-button {
|
||||
display: none;
|
||||
@ -348,7 +348,7 @@
|
||||
}
|
||||
|
||||
/* ::::: splitmenu highlight style that imitates Windows 7 start menu ::::: */
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
.splitmenu-menuitem,
|
||||
.splitmenu-menu {
|
||||
-moz-appearance: none;
|
||||
|
@ -165,14 +165,14 @@
|
||||
margin: 0 0 2px;
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-classic) {
|
||||
@media (-moz-windows-classic) {
|
||||
#appmenu-button {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
%ifndef WINSTRIPE_AERO
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
#main-window[sizemode="normal"] #appmenu-button {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
@ -315,7 +315,7 @@
|
||||
-moz-border-end: 1px solid ThreeDShadow;
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
#appmenu-popup {
|
||||
-moz-appearance: none;
|
||||
background: white;
|
||||
@ -483,7 +483,7 @@
|
||||
-moz-appearance: -moz-window-titlebar-maximized;
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-classic) {
|
||||
@media (-moz-windows-classic) {
|
||||
#main-window[sizemode="normal"] > #titlebar > #titlebar-content > #appmenu-button-container {
|
||||
margin-top: 4px;
|
||||
}
|
||||
@ -1214,7 +1214,7 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
|
||||
-moz-padding-end: 2px;
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
#urlbar,
|
||||
.searchbar-textbox {
|
||||
@navbarTextboxCustomBorder@
|
||||
@ -1712,7 +1712,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
||||
margin: 16px 0 -2px;
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
.panel-promo-box {
|
||||
margin: 8px -16px -16px;
|
||||
padding: 8px 16px;
|
||||
@ -1795,7 +1795,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
||||
}
|
||||
|
||||
%ifndef WINSTRIPE_AERO
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
#main-window[sizemode=normal] #TabsToolbar {
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
@ -1827,7 +1827,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
||||
}
|
||||
|
||||
%ifndef WINSTRIPE_AERO
|
||||
@media all and (-moz-windows-theme: luna-blue) {
|
||||
@media (-moz-windows-theme: luna-blue) {
|
||||
.tabbrowser-tab,
|
||||
.tabs-newtab-button {
|
||||
background-image: @toolbarShadowOnTab@,
|
||||
@ -1956,7 +1956,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
||||
|
||||
/* Tab scrollbox arrow, tabstrip new tab and all-tabs buttons */
|
||||
|
||||
@media all and (-moz-touch-enabled) {
|
||||
@media (-moz-touch-enabled) {
|
||||
.tabbrowser-arrowscrollbox > .scrollbutton-up,
|
||||
.tabbrowser-arrowscrollbox > .scrollbutton-down,
|
||||
#TabsToolbar .toolbarbutton-1 {
|
||||
|
@ -21,7 +21,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-compositor) {
|
||||
@media (-moz-windows-compositor) {
|
||||
#placesToolbox {
|
||||
border-top: none;
|
||||
}
|
||||
@ -31,7 +31,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
#placesView,
|
||||
#searchModifiers,
|
||||
#infoPane,
|
||||
|
@ -44,13 +44,22 @@ public interface Actions {
|
||||
public enum SpecialKey {
|
||||
DOWN, UP, LEFT, RIGHT, ENTER
|
||||
}
|
||||
|
||||
public interface EventExpecter {
|
||||
/** Blocks until the event has been received. Subsequent calls will return immediately. */
|
||||
public void blockForEvent();
|
||||
/** Polls to see if the event has been received. Once this returns true, subsequent calls will also return true. */
|
||||
public boolean eventReceived();
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a gecko event to be sent from the Gecko instance.
|
||||
* Listens for a gecko event to be sent from the Gecko instance.
|
||||
* The returned object can be used to test if the event has been
|
||||
* received. Note that only one event is listened for.
|
||||
*
|
||||
* @param geckoEvent The geckoEvent JSONObject's type
|
||||
*/
|
||||
|
||||
void waitForGeckoEvent(String geckoEvent);
|
||||
EventExpecter expectGeckoEvent(String geckoEvent);
|
||||
// Send the string kewsToSend to the application
|
||||
void sendKeys(String keysToSend);
|
||||
//Send any of the above keys to the element
|
||||
|
@ -38,17 +38,20 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import java.util.List;
|
||||
import android.app.Activity;
|
||||
|
||||
public interface Driver {
|
||||
/**
|
||||
* Find the first Element using the given method.
|
||||
*
|
||||
* @param activity The activity the element belongs to
|
||||
* @param name The name of the element
|
||||
* @return The first matching element on the current context
|
||||
* @throws RoboCopException If no matching elements are found
|
||||
*/
|
||||
Element findElement(String name);
|
||||
Element findElement(Activity activity, String name);
|
||||
|
||||
/**
|
||||
* Sets up scroll handling so that data is received from the extension.
|
||||
|
@ -84,9 +84,6 @@ public class FennecNativeActions implements Actions {
|
||||
private Method sendGE;
|
||||
|
||||
|
||||
// If waiting for an event.
|
||||
private SynchronousQueue waitqueue = new SynchronousQueue<Boolean>();
|
||||
|
||||
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation){
|
||||
this.solo = robocop;
|
||||
this.instr = instrumentation;
|
||||
@ -116,7 +113,12 @@ public class FennecNativeActions implements Actions {
|
||||
}
|
||||
|
||||
class wakeInvocationHandler implements InvocationHandler {
|
||||
public wakeInvocationHandler(){};
|
||||
private final GeckoEventExpecter mEventExpecter;
|
||||
|
||||
public wakeInvocationHandler(GeckoEventExpecter expecter) {
|
||||
mEventExpecter = expecter;
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) {
|
||||
String methodName = method.getName();
|
||||
//Depending on the method, return a completely different type.
|
||||
@ -133,12 +135,54 @@ public class FennecNativeActions implements Actions {
|
||||
return 314;
|
||||
}
|
||||
Log.i("Robocop", "Waking up on "+methodName);
|
||||
waitqueue.offer(new Boolean(true));
|
||||
mEventExpecter.notifyOfEvent();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class GeckoEventExpecter implements EventExpecter {
|
||||
private final String mGeckoEvent;
|
||||
private final Object[] mRegistrationParams;
|
||||
private boolean mEventReceived;
|
||||
|
||||
GeckoEventExpecter(String geckoEvent, Object[] registrationParams) {
|
||||
mGeckoEvent = geckoEvent;
|
||||
mRegistrationParams = registrationParams;
|
||||
}
|
||||
|
||||
public synchronized void blockForEvent() {
|
||||
while (! mEventReceived) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Log.i("Robocop", "unblocked on expecter for " + mGeckoEvent);
|
||||
}
|
||||
|
||||
public synchronized boolean eventReceived() {
|
||||
return mEventReceived;
|
||||
}
|
||||
|
||||
void notifyOfEvent() {
|
||||
try {
|
||||
unregisterGEL.invoke(null, mRegistrationParams);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Log.i("Robocop", "received event " + mGeckoEvent);
|
||||
synchronized (this) {
|
||||
mEventReceived = true;
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void waitForGeckoEvent(String geckoEvent) {
|
||||
public EventExpecter expectGeckoEvent(String geckoEvent) {
|
||||
Log.i("Robocop", "waiting for "+geckoEvent);
|
||||
try {
|
||||
Class [] interfaces = new Class[1];
|
||||
@ -146,21 +190,19 @@ public class FennecNativeActions implements Actions {
|
||||
Object[] finalParams = new Object[2];
|
||||
finalParams[0] = geckoEvent;
|
||||
|
||||
wakeInvocationHandler wIH = new wakeInvocationHandler();
|
||||
GeckoEventExpecter expecter = new GeckoEventExpecter(geckoEvent, finalParams);
|
||||
wakeInvocationHandler wIH = new wakeInvocationHandler(expecter);
|
||||
Object proxy = Proxy.newProxyInstance(classLoader, interfaces, wIH);
|
||||
finalParams[1] = proxy;
|
||||
registerGEL.invoke(null, finalParams);
|
||||
|
||||
waitqueue.take();
|
||||
unregisterGEL.invoke(null, finalParams);
|
||||
return expecter;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Log.i("Robocop", "wait ends for: "+geckoEvent);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void sendSpecialKey(SpecialKey button) {
|
||||
|
@ -167,8 +167,7 @@ public class FennecNativeDriver implements Driver {
|
||||
return geckoWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element findElement(String name) {
|
||||
public Element findElement(Activity activity, String name) {
|
||||
if (name == null)
|
||||
throw new IllegalArgumentException("Can not findElements when passed a null");
|
||||
if (locators.containsKey(name)){
|
||||
|
@ -56,28 +56,26 @@ import com.jayway.android.robotium.solo.Solo;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
|
||||
public class FennecNativeElement implements Element {
|
||||
private final Activity mActivity;
|
||||
private Integer id;
|
||||
private Activity currentActivity;
|
||||
private Solo robocop;
|
||||
|
||||
public FennecNativeElement(Integer id, Activity activity, Solo solo){
|
||||
this.id = id;
|
||||
mActivity = activity;
|
||||
robocop = solo;
|
||||
currentActivity = activity;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void click() {
|
||||
final SynchronousQueue syncQueue = new SynchronousQueue();
|
||||
currentActivity = robocop.getCurrentActivity();
|
||||
currentActivity.runOnUiThread(
|
||||
mActivity.runOnUiThread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
View view = (View)currentActivity.findViewById(id);
|
||||
View view = (View)mActivity.findViewById(id);
|
||||
if(view != null) {
|
||||
view.performClick();
|
||||
} else {
|
||||
@ -94,16 +92,13 @@ public class FennecNativeElement implements Element {
|
||||
}
|
||||
|
||||
private Object text;
|
||||
private Activity elementActivity;
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
elementActivity = robocop.getCurrentActivity();
|
||||
final SynchronousQueue syncQueue = new SynchronousQueue();
|
||||
elementActivity.runOnUiThread(
|
||||
mActivity.runOnUiThread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
View v = elementActivity.findViewById(id);
|
||||
View v = mActivity.findViewById(id);
|
||||
if(v instanceof EditText) {
|
||||
EditText et = (EditText)v;
|
||||
text = et.getEditableText();
|
||||
@ -143,15 +138,13 @@ public class FennecNativeElement implements Element {
|
||||
|
||||
private boolean displayed;
|
||||
|
||||
@Override
|
||||
public boolean isDisplayed() {
|
||||
final SynchronousQueue syncQueue = new SynchronousQueue();
|
||||
currentActivity = robocop.getCurrentActivity();
|
||||
displayed = false;
|
||||
currentActivity.runOnUiThread(
|
||||
mActivity.runOnUiThread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
View view = (View)currentActivity.findViewById(id);
|
||||
View view = (View)mActivity.findViewById(id);
|
||||
if(view != null) {
|
||||
displayed = true;
|
||||
}
|
||||
|
@ -8907,16 +8907,9 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
|
||||
// Remember this is the requesting full-screen document.
|
||||
sFullScreenDoc = do_GetWeakReference(static_cast<nsIDocument*>(this));
|
||||
|
||||
// Make the window full-screen. Note we must make the state changes above
|
||||
// before making the window full-screen, as then the document reports as
|
||||
// being in full-screen mode when the chrome "fullscreen" event fires,
|
||||
// enabling chrome to distinguish between browser and dom full-screen
|
||||
// modes. Also note that nsGlobalWindow::SetFullScreen() (which
|
||||
// SetWindowFullScreen() calls) proxies to the root window in its hierarchy,
|
||||
// and does not operate on the a per-nsIDOMWindow basis.
|
||||
SetWindowFullScreen(this, true);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Note assertions must run before SetWindowFullScreen() as that does
|
||||
// synchronous event dispatch which can run script which exits full-screen!
|
||||
NS_ASSERTION(GetFullScreenElement() == aElement,
|
||||
"Full-screen element should be the requested element!");
|
||||
NS_ASSERTION(IsFullScreenDoc(), "Should be full-screen doc");
|
||||
@ -8926,6 +8919,15 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
|
||||
NS_ASSERTION(c->AsElement() == aElement,
|
||||
"GetMozFullScreenElement should match GetFullScreenElement()");
|
||||
#endif
|
||||
|
||||
// Make the window full-screen. Note we must make the state changes above
|
||||
// before making the window full-screen, as then the document reports as
|
||||
// being in full-screen mode when the chrome "fullscreen" event fires,
|
||||
// enabling chrome to distinguish between browser and dom full-screen
|
||||
// modes. Also note that nsGlobalWindow::SetFullScreen() (which
|
||||
// SetWindowFullScreen() calls) proxies to the root window in its hierarchy,
|
||||
// and does not operate on the a per-nsIDOMWindow basis.
|
||||
SetWindowFullScreen(this, true);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1568,6 +1568,7 @@ nsWebSocket::Cancel(nsresult aStatus)
|
||||
return NS_OK;
|
||||
|
||||
ConsoleError();
|
||||
mClientReasonCode = nsIWebSocketChannel::CLOSE_GOING_AWAY;
|
||||
return CloseConnection();
|
||||
}
|
||||
|
||||
|
@ -302,6 +302,11 @@ NS_IMETHODIMP nsHTMLMediaElement::MediaLoadListener::OnStartRequest(nsIRequest*
|
||||
{
|
||||
nsContentUtils::UnregisterShutdownObserver(this);
|
||||
|
||||
if (!mElement) {
|
||||
// We've been notified by the shutdown observer, and are shutting down.
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
|
||||
// The element is only needed until we've had a chance to call
|
||||
// InitializeDecoderForChannel. So make sure mElement is cleared here.
|
||||
nsRefPtr<nsHTMLMediaElement> element;
|
||||
|
@ -273,7 +273,7 @@ nsresult nsBuiltinDecoder::Play()
|
||||
* Returns true if aValue is inside a range of aRanges, and put the range
|
||||
* index in aIntervalIndex if it is not null.
|
||||
* If aValue is not inside a range, false is returned, and aIntervalIndex, if
|
||||
* not null, is set to the index of the range which ends immediatly before aValue
|
||||
* not null, is set to the index of the range which ends immediately before aValue
|
||||
* (and can be -1 if aValue is before aRanges.Start(0)).
|
||||
*/
|
||||
static bool IsInRanges(nsTimeRanges& aRanges, double aValue, PRInt32& aIntervalIndex) {
|
||||
@ -315,30 +315,32 @@ nsresult nsBuiltinDecoder::Seek(double aTime)
|
||||
}
|
||||
|
||||
// If the position we want to seek to is not in a seekable range, we seek
|
||||
// to the closest position in the seekable ranges instead . If two positions
|
||||
// are equaly close, we seek to the closest position from the currentTime.
|
||||
// to the closest position in the seekable ranges instead. If two positions
|
||||
// are equally close, we seek to the closest position from the currentTime.
|
||||
// See seeking spec, point 7 :
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#seeking
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#seeking
|
||||
PRInt32 range = 0;
|
||||
if (!IsInRanges(seekable, aTime, range)) {
|
||||
if (range != -1) {
|
||||
double leftBound, rightBound;
|
||||
res = seekable.End(range, &leftBound);
|
||||
NS_ENSURE_SUCCESS(res, NS_OK);
|
||||
double distanceLeft = NS_ABS(leftBound - aTime);
|
||||
|
||||
double distanceRight = -1;
|
||||
if (range + 1 < length) {
|
||||
res = seekable.Start(range+1, &rightBound);
|
||||
double leftBound, rightBound;
|
||||
res = seekable.End(range, &leftBound);
|
||||
NS_ENSURE_SUCCESS(res, NS_OK);
|
||||
res = seekable.Start(range + 1, &rightBound);
|
||||
NS_ENSURE_SUCCESS(res, NS_OK);
|
||||
double distanceLeft = NS_ABS(leftBound - aTime);
|
||||
double distanceRight = NS_ABS(rightBound - aTime);
|
||||
if (distanceLeft == distanceRight) {
|
||||
distanceLeft = NS_ABS(leftBound - mCurrentTime);
|
||||
distanceRight = NS_ABS(rightBound - mCurrentTime);
|
||||
}
|
||||
aTime = (distanceLeft < distanceRight) ? leftBound : rightBound;
|
||||
} else {
|
||||
// Seek target is after the end last range in seekable data.
|
||||
// Clamp the seek target to the end of the last seekable range.
|
||||
res = seekable.End(length - 1, &aTime);
|
||||
NS_ENSURE_SUCCESS(res, NS_OK);
|
||||
distanceRight = NS_ABS(rightBound - aTime);
|
||||
}
|
||||
|
||||
if (distanceLeft == distanceRight) {
|
||||
distanceLeft = NS_ABS(leftBound - mCurrentTime);
|
||||
distanceRight = NS_ABS(rightBound - mCurrentTime);
|
||||
}
|
||||
aTime = (distanceLeft < distanceRight) ? leftBound : rightBound;
|
||||
} else {
|
||||
// aTime is before the first range in |seekable|, the closest point we can
|
||||
// seek to is the start of the first range.
|
||||
|
@ -1124,6 +1124,33 @@ void nsBuiltinDecoderStateMachine::ResetPlayback()
|
||||
mAudioCompleted = false;
|
||||
}
|
||||
|
||||
void nsBuiltinDecoderStateMachine::NotifyDataArrived(const char* aBuffer,
|
||||
PRUint32 aLength,
|
||||
PRUint32 aOffset)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
mReader->NotifyDataArrived(aBuffer, aLength, aOffset);
|
||||
|
||||
// While playing an unseekable stream of unknown duration, mEndTime is
|
||||
// updated (in AdvanceFrame()) as we play. But if data is being downloaded
|
||||
// faster than played, mEndTime won't reflect the end of playable data
|
||||
// since we haven't played the frame at the end of buffered data. So update
|
||||
// mEndTime here as new data is downloaded to prevent such a lag.
|
||||
nsTimeRanges buffered;
|
||||
if (mDecoder->IsInfinite() &&
|
||||
NS_SUCCEEDED(mDecoder->GetBuffered(&buffered)))
|
||||
{
|
||||
PRUint32 length = 0;
|
||||
buffered.GetLength(&length);
|
||||
if (length) {
|
||||
double end = 0;
|
||||
buffered.End(length - 1, &end);
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mEndTime = NS_MAX<PRInt64>(mEndTime, end * USECS_PER_S);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsBuiltinDecoderStateMachine::Seek(double aTime)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
@ -1505,7 +1532,11 @@ void nsBuiltinDecoderStateMachine::DecodeSeek()
|
||||
// if we need to seek again.
|
||||
|
||||
nsCOMPtr<nsIRunnable> stopEvent;
|
||||
if (GetMediaTime() == mEndTime) {
|
||||
bool isLiveStream = mDecoder->GetStream()->GetLength() == -1;
|
||||
if (GetMediaTime() == mEndTime && !isLiveStream) {
|
||||
// Seeked to end of media, move to COMPLETED state. Note we don't do
|
||||
// this if we're playing a live stream, since the end of media will advance
|
||||
// once we download more data!
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to COMPLETED",
|
||||
mDecoder.get(), seekTime));
|
||||
stopEvent = NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::SeekingStoppedAtEnd);
|
||||
|
@ -223,10 +223,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) {
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
mReader->NotifyDataArrived(aBuffer, aLength, aOffset);
|
||||
}
|
||||
void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset);
|
||||
|
||||
PRInt64 GetEndMediaTime() const {
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
|
@ -1619,6 +1619,55 @@ nsDOMWindowUtils::GetLayerManagerType(nsAString& aType)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::StartFrameTimeRecording()
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
LayerManager *mgr = widget->GetLayerManager();
|
||||
if (!mgr)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mgr->StartFrameTimeRecording();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::StopFrameTimeRecording(PRUint32 *frameCount NS_OUTPARAM, float **frames NS_OUTPARAM)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(frameCount);
|
||||
NS_ENSURE_ARG_POINTER(frames);
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
LayerManager *mgr = widget->GetLayerManager();
|
||||
if (!mgr)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsTArray<float> frameTimes = mgr->StopFrameTimeRecording();
|
||||
|
||||
*frames = nsnull;
|
||||
*frameCount = frameTimes.Length();
|
||||
|
||||
if (*frameCount != 0) {
|
||||
*frames = (float*)nsMemory::Alloc(*frameCount * sizeof(float*));
|
||||
if (!*frames)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
/* copy over the frame times into the array we just allocated */
|
||||
for (PRUint32 i = 0; i < *frameCount; i++) {
|
||||
(*frames)[i] = frameTimes[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool
|
||||
ComputeAnimationValue(nsCSSProperty aProperty,
|
||||
Element* aElement,
|
||||
|
@ -252,13 +252,6 @@ IndexedDatabaseManager::GetOrCreate()
|
||||
false);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
// We don't really need this callback but we want the observer service to
|
||||
// hold us alive until XPCOM shutdown. That way other consumers can continue
|
||||
// to use this service until shutdown.
|
||||
rv = obs->AddObserver(instance, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID,
|
||||
false);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
// Make a lazy thread for any IO we need (like clearing or enumerating the
|
||||
// contents of indexedDB database directories).
|
||||
instance->mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
|
||||
@ -1224,7 +1217,7 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject,
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID)) {
|
||||
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
|
||||
// Setting this flag prevents the service from being recreated and prevents
|
||||
// further databases from being created.
|
||||
if (PR_ATOMIC_SET(&gShutdown, 1)) {
|
||||
@ -1279,11 +1272,6 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
|
||||
// We're dying now.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Unknown topic!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ interface nsIDOMBlob;
|
||||
interface nsIDOMFile;
|
||||
interface nsIFile;
|
||||
|
||||
[scriptable, uuid(c1fa9c82-acf2-4b27-8ca7-7d1864e606af)]
|
||||
[scriptable, uuid(15fcceb0-37ea-11e1-b86c-0800200c9a66)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -838,6 +838,9 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
*/
|
||||
readonly attribute AString layerManagerType;
|
||||
|
||||
void startFrameTimeRecording();
|
||||
void stopFrameTimeRecording([optional] out unsigned long frameCount,
|
||||
[retval, array, size_is(frameCount)] out float frameTime);
|
||||
/**
|
||||
* The DPI of the display
|
||||
*/
|
||||
|
@ -208,7 +208,7 @@ nsDOMStoragePersistentDB::Init(const nsString& aDatabaseName)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"PRAGMA temp_store = MEMORY"));
|
||||
MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA temp_store = MEMORY"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mozStorageTransaction transaction(mConnection, false);
|
||||
|
@ -561,6 +561,31 @@ PlanarYCbCrImage::CopyData(Data& aDest, gfxIntSize& aDestSize,
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void
|
||||
LayerManager::StartFrameTimeRecording()
|
||||
{
|
||||
mLastFrameTime = TimeStamp::Now();
|
||||
}
|
||||
|
||||
void
|
||||
LayerManager::PostPresent()
|
||||
{
|
||||
if (!mLastFrameTime.IsNull()) {
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
mFrameTimes.AppendElement((now - mLastFrameTime).ToMilliseconds());
|
||||
mLastFrameTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<float>
|
||||
LayerManager::StopFrameTimeRecording()
|
||||
{
|
||||
mLastFrameTime = TimeStamp();
|
||||
nsTArray<float> result = mFrameTimes;
|
||||
mFrameTimes.Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef MOZ_LAYERS_HAVE_LOG
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
#if defined(DEBUG) || defined(PR_LOGGING)
|
||||
# include <stdio.h> // FILE
|
||||
@ -512,6 +513,11 @@ public:
|
||||
*/
|
||||
void LogSelf(const char* aPrefix="");
|
||||
|
||||
void StartFrameTimeRecording();
|
||||
nsTArray<float> StopFrameTimeRecording();
|
||||
|
||||
void PostPresent();
|
||||
|
||||
static bool IsLogEnabled();
|
||||
static PRLogModuleInfo* GetLog() { return sLog; }
|
||||
|
||||
@ -532,6 +538,9 @@ protected:
|
||||
|
||||
static void InitLog();
|
||||
static PRLogModuleInfo* sLog;
|
||||
private:
|
||||
TimeStamp mLastFrameTime;
|
||||
nsTArray<float> mFrameTimes;
|
||||
};
|
||||
|
||||
class ThebesLayer;
|
||||
|
@ -778,6 +778,7 @@ LayerManagerD3D10::Render()
|
||||
} else {
|
||||
mSwapChain->Present(0, 0);
|
||||
}
|
||||
LayerManager::PostPresent();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -354,6 +354,7 @@ LayerManagerD3D9::Render()
|
||||
(r = iter.Next()) != nsnull;) {
|
||||
mSwapChain->Present(*r);
|
||||
}
|
||||
LayerManager::PostPresent();
|
||||
} else {
|
||||
PaintToTarget();
|
||||
}
|
||||
|
@ -819,6 +819,7 @@ LayerManagerOGL::Render()
|
||||
|
||||
if (mGLContext->IsDoubleBuffered()) {
|
||||
mGLContext->SwapBuffers();
|
||||
LayerManager::PostPresent();
|
||||
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
return;
|
||||
}
|
||||
|
@ -774,7 +774,7 @@ struct ParamTraits<LogData> {
|
||||
int type;
|
||||
bool result =
|
||||
ReadParam(m, iter, &r->channel) &&
|
||||
ReadParam(m, iter, &r->routing_id);
|
||||
ReadParam(m, iter, &r->routing_id) &&
|
||||
ReadParam(m, iter, &type) &&
|
||||
ReadParam(m, iter, &r->flags) &&
|
||||
ReadParam(m, iter, &r->sent) &&
|
||||
|
8
js/src/jit-test/tests/basic/write-frozen-property.js
Normal file
8
js/src/jit-test/tests/basic/write-frozen-property.js
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
function foo(x) {
|
||||
x.a = 10;
|
||||
assertEq(x.a, 0);
|
||||
}
|
||||
x = {a:0,b:1};
|
||||
Object.freeze(x);
|
||||
foo(x);
|
@ -1912,7 +1912,7 @@ obj_keys(JSContext *cx, uintN argc, Value *vp)
|
||||
for (size_t i = 0, len = props.length(); i < len; i++) {
|
||||
jsid id = props[i];
|
||||
if (JSID_IS_STRING(id)) {
|
||||
JS_ALWAYS_TRUE(vals.append(StringValue(JSID_TO_STRING(id))));
|
||||
vals.infallibleAppend(StringValue(JSID_TO_STRING(id)));
|
||||
} else if (JSID_IS_INT(id)) {
|
||||
JSString *str = js_IntToString(cx, JSID_TO_INT(id));
|
||||
if (!str)
|
||||
@ -1924,7 +1924,7 @@ obj_keys(JSContext *cx, uintN argc, Value *vp)
|
||||
}
|
||||
|
||||
JS_ASSERT(props.length() <= UINT32_MAX);
|
||||
JSObject *aobj = NewDenseCopiedArray(cx, jsuint(vals.length()), vals.begin());
|
||||
JSObject *aobj = NewDenseCopiedArray(cx, uint32_t(vals.length()), vals.begin());
|
||||
if (!aobj)
|
||||
return false;
|
||||
vp->setObject(*aobj);
|
||||
@ -2698,6 +2698,15 @@ obj_preventExtensions(JSContext *cx, uintN argc, Value *vp)
|
||||
return obj->preventExtensions(cx, &props);
|
||||
}
|
||||
|
||||
/* static */ inline uintN
|
||||
JSObject::getSealedOrFrozenAttributes(uintN attrs, ImmutabilityType it)
|
||||
{
|
||||
/* Make all attributes permanent; if freezing, make data attributes read-only. */
|
||||
if (it == FREEZE && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
|
||||
return JSPROP_PERMANENT | JSPROP_READONLY;
|
||||
return JSPROP_PERMANENT;
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it)
|
||||
{
|
||||
@ -2718,27 +2727,62 @@ JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it)
|
||||
/* preventExtensions must slowify dense arrays, so we can assign to holes without checks. */
|
||||
JS_ASSERT(!self->isDenseArray());
|
||||
|
||||
for (size_t i = 0, len = props.length(); i < len; i++) {
|
||||
jsid id = props[i];
|
||||
|
||||
uintN attrs;
|
||||
if (!self->getGenericAttributes(cx, id, &attrs))
|
||||
if (isNative() && !inDictionaryMode()) {
|
||||
/*
|
||||
* Seal/freeze non-dictionary objects by constructing a new shape
|
||||
* hierarchy mirroring the original one, which can be shared if many
|
||||
* objects with the same structure are sealed/frozen. If we use the
|
||||
* generic path below then any non-empty object will be converted to
|
||||
* dictionary mode.
|
||||
*/
|
||||
Shape *last = EmptyShape::getInitialShape(cx, self->getClass(),
|
||||
self->getProto(),
|
||||
self->getParent(),
|
||||
self->getAllocKind(),
|
||||
self->lastProperty()->getObjectFlags());
|
||||
if (!last)
|
||||
return false;
|
||||
|
||||
/* Make all attributes permanent; if freezing, make data attributes read-only. */
|
||||
uintN new_attrs;
|
||||
if (it == FREEZE && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
|
||||
new_attrs = JSPROP_PERMANENT | JSPROP_READONLY;
|
||||
else
|
||||
new_attrs = JSPROP_PERMANENT;
|
||||
/* Get an in order list of the shapes in this object. */
|
||||
AutoShapeVector shapes(cx);
|
||||
for (Shape::Range r = self->lastProperty()->all(); !r.empty(); r.popFront()) {
|
||||
if (!shapes.append(&r.front()))
|
||||
return false;
|
||||
}
|
||||
Reverse(shapes.begin(), shapes.end());
|
||||
|
||||
/* If we already have the attributes we need, skip the setAttributes call. */
|
||||
if ((attrs | new_attrs) == attrs)
|
||||
continue;
|
||||
for (size_t i = 0; i < shapes.length(); i++) {
|
||||
StackShape child(shapes[i]);
|
||||
child.attrs |= getSealedOrFrozenAttributes(child.attrs, it);
|
||||
|
||||
attrs |= new_attrs;
|
||||
if (!self->setGenericAttributes(cx, id, &attrs))
|
||||
return false;
|
||||
if (!JSID_IS_EMPTY(child.propid))
|
||||
MarkTypePropertyConfigured(cx, self, child.propid);
|
||||
|
||||
last = JS_PROPERTY_TREE(cx).getChild(cx, last, self->numFixedSlots(), child);
|
||||
if (!last)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JS_ASSERT(self->lastProperty()->slotSpan() == last->slotSpan());
|
||||
JS_ALWAYS_TRUE(setLastProperty(cx, last));
|
||||
} else {
|
||||
for (size_t i = 0; i < props.length(); i++) {
|
||||
jsid id = props[i];
|
||||
|
||||
uintN attrs;
|
||||
if (!self->getGenericAttributes(cx, id, &attrs))
|
||||
return false;
|
||||
|
||||
uintN new_attrs = getSealedOrFrozenAttributes(attrs, it);
|
||||
|
||||
/* If we already have the attributes we need, skip the setAttributes call. */
|
||||
if ((attrs | new_attrs) == attrs)
|
||||
continue;
|
||||
|
||||
attrs |= new_attrs;
|
||||
if (!self->setGenericAttributes(cx, id, &attrs))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -968,6 +968,8 @@ struct JSObject : js::gc::Cell
|
||||
|
||||
bool isSealedOrFrozen(JSContext *cx, ImmutabilityType it, bool *resultp);
|
||||
|
||||
static inline uintN getSealedOrFrozenAttributes(uintN attrs, ImmutabilityType it);
|
||||
|
||||
inline void *&privateRef(uint32_t nfixed) const;
|
||||
|
||||
public:
|
||||
|
@ -300,7 +300,6 @@ JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp
|
||||
{
|
||||
JS_ASSERT(nativeContains(cx, shape));
|
||||
JS_ASSERT(shape.isMethod());
|
||||
JS_ASSERT(shape.writable());
|
||||
JS_ASSERT(shape.hasSlot());
|
||||
JS_ASSERT(shape.hasDefaultSetter());
|
||||
JS_ASSERT(!isGlobal()); /* i.e. we are not changing the global shape */
|
||||
|
@ -1071,7 +1071,7 @@ JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *n
|
||||
RootObject selfRoot(cx, &self);
|
||||
RootShape newRoot(cx, &newShape);
|
||||
if (!toDictionaryMode(cx))
|
||||
return false;
|
||||
return NULL;
|
||||
oldShape = lastProperty();
|
||||
}
|
||||
|
||||
@ -1080,7 +1080,7 @@ JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *n
|
||||
RootShape oldRoot(cx, &oldShape);
|
||||
newShape = js_NewGCShape(cx);
|
||||
if (!newShape)
|
||||
return false;
|
||||
return NULL;
|
||||
new (newShape) Shape(oldShape->base()->unowned(), 0);
|
||||
}
|
||||
|
||||
|
@ -1916,7 +1916,7 @@ DoReplace(JSContext *cx, RegExpStatics *res, ReplaceData &rdata)
|
||||
dp++;
|
||||
}
|
||||
}
|
||||
JS_ALWAYS_TRUE(rdata.sb.append(cp, repstr->length() - (cp - bp)));
|
||||
rdata.sb.infallibleAppend(cp, repstr->length() - (cp - bp));
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -882,8 +882,11 @@ FrameState::discardForJoin(RegisterAllocation *&alloc, uint32_t stackDepth)
|
||||
}
|
||||
|
||||
regstate(reg).associate(fe, RematInfo::DATA);
|
||||
if (!alloc->synced(reg))
|
||||
if (!alloc->synced(reg)) {
|
||||
fe->data.unsync();
|
||||
if (!reg.isReg())
|
||||
fe->type.unsync();
|
||||
}
|
||||
}
|
||||
|
||||
a->sp = a->spBase + stackDepth;
|
||||
|
@ -5064,6 +5064,9 @@ ProcessArgs(JSContext *cx, JSObject *obj, OptionParser *op)
|
||||
if (op->getBoolOption('a'))
|
||||
JS_ToggleOptions(cx, JSOPTION_METHODJIT_ALWAYS);
|
||||
|
||||
if (op->getBoolOption('c'))
|
||||
compileOnly = true;
|
||||
|
||||
if (op->getBoolOption('m')) {
|
||||
enableMethodJit = true;
|
||||
JS_ToggleOptions(cx, JSOPTION_METHODJIT);
|
||||
@ -5331,6 +5334,7 @@ main(int argc, char **argv, char **envp)
|
||||
|| !op.addBoolOption('i', "shell", "Enter prompt after running code")
|
||||
|| !op.addBoolOption('m', "methodjit", "Enable the JaegerMonkey method JIT")
|
||||
|| !op.addBoolOption('n', "typeinfer", "Enable type inference")
|
||||
|| !op.addBoolOption('c', "compileonly", "Only compile, don't run (syntax checking mode)")
|
||||
|| !op.addBoolOption('d', "debugjit", "Enable runtime debug mode for method JIT code")
|
||||
|| !op.addBoolOption('a', "always-mjit",
|
||||
"Do not try to run in the interpreter before method jitting.")
|
||||
|
@ -437,6 +437,7 @@ abstract public class GeckoApp
|
||||
MenuItem share = aMenu.findItem(R.id.share);
|
||||
MenuItem agentMode = aMenu.findItem(R.id.agent_mode);
|
||||
MenuItem saveAsPDF = aMenu.findItem(R.id.save_as_pdf);
|
||||
MenuItem downloads = aMenu.findItem(R.id.downloads);
|
||||
|
||||
if (tab == null) {
|
||||
bookmark.setEnabled(false);
|
||||
@ -453,11 +454,9 @@ abstract public class GeckoApp
|
||||
if (tab.isBookmark()) {
|
||||
bookmark.setChecked(true);
|
||||
bookmark.setIcon(R.drawable.ic_menu_bookmark_remove);
|
||||
bookmark.setTitle(R.string.bookmark_remove);
|
||||
} else {
|
||||
bookmark.setChecked(false);
|
||||
bookmark.setIcon(R.drawable.ic_menu_bookmark_add);
|
||||
bookmark.setTitle(R.string.bookmark_add);
|
||||
}
|
||||
|
||||
forward.setEnabled(tab.canDoForward());
|
||||
@ -473,6 +472,10 @@ abstract public class GeckoApp
|
||||
saveAsPDF.setEnabled(!(tab.getURL().equals("about:home") ||
|
||||
tab.getContentType().equals("application/vnd.mozilla.xul+xml")));
|
||||
|
||||
// DownloadManager support is tied to level 12 and higher
|
||||
if (Build.VERSION.SDK_INT < 12)
|
||||
downloads.setVisible(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -498,12 +501,10 @@ abstract public class GeckoApp
|
||||
tab.removeBookmark();
|
||||
Toast.makeText(this, R.string.bookmark_removed, Toast.LENGTH_SHORT).show();
|
||||
item.setIcon(R.drawable.ic_menu_bookmark_add);
|
||||
item.setTitle(R.string.bookmark_add);
|
||||
} else {
|
||||
tab.addBookmark();
|
||||
Toast.makeText(this, R.string.bookmark_added, Toast.LENGTH_SHORT).show();
|
||||
item.setIcon(R.drawable.ic_menu_bookmark_remove);
|
||||
item.setTitle(R.string.bookmark_remove);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -533,6 +534,10 @@ abstract public class GeckoApp
|
||||
case R.id.addons:
|
||||
loadUrlInTab("about:addons");
|
||||
return true;
|
||||
case R.id.downloads:
|
||||
intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.agent_mode:
|
||||
Tab selectedTab = Tabs.getInstance().getSelectedTab();
|
||||
if (selectedTab == null)
|
||||
@ -975,6 +980,13 @@ abstract public class GeckoApp
|
||||
String host = message.getString("host");
|
||||
JSONArray permissions = message.getJSONArray("permissions");
|
||||
showSiteSettingsDialog(host, permissions);
|
||||
} else if (event.equals("Downloads:Done")) {
|
||||
String displayName = message.getString("displayName");
|
||||
String path = message.getString("path");
|
||||
String mimeType = message.getString("mimeType");
|
||||
int size = message.getInt("size");
|
||||
|
||||
handleDownloadDone(displayName, path, mimeType, size);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
|
||||
@ -1302,6 +1314,17 @@ abstract public class GeckoApp
|
||||
tabs.closeTab(tab);
|
||||
}
|
||||
|
||||
void handleDownloadDone(String displayName, String path, String mimeType, int size) {
|
||||
// DownloadManager.addCompletedDownload is supported in level 12 and higher
|
||||
if (Build.VERSION.SDK_INT >= 12) {
|
||||
DownloadManager dm = (DownloadManager) mAppContext.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
dm.addCompletedDownload(displayName, displayName,
|
||||
false /* do not use media scanner */,
|
||||
mimeType, path, size,
|
||||
false /* no notification */);
|
||||
}
|
||||
}
|
||||
|
||||
void addPluginView(final View view,
|
||||
final double x, final double y,
|
||||
final double w, final double h) {
|
||||
@ -1559,6 +1582,7 @@ abstract public class GeckoApp
|
||||
GeckoAppShell.registerGeckoEventListener("AgentMode:Changed", GeckoApp.mAppContext);
|
||||
GeckoAppShell.registerGeckoEventListener("FormAssist:AutoComplete", GeckoApp.mAppContext);
|
||||
GeckoAppShell.registerGeckoEventListener("Permissions:Data", GeckoApp.mAppContext);
|
||||
GeckoAppShell.registerGeckoEventListener("Downloads:Done", GeckoApp.mAppContext);
|
||||
|
||||
mConnectivityFilter = new IntentFilter();
|
||||
mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
@ -1794,6 +1818,7 @@ abstract public class GeckoApp
|
||||
GeckoAppShell.unregisterGeckoEventListener("AgentMode:Changed", GeckoApp.mAppContext);
|
||||
GeckoAppShell.unregisterGeckoEventListener("FormAssist:AutoComplete", GeckoApp.mAppContext);
|
||||
GeckoAppShell.unregisterGeckoEventListener("Permissions:Data", GeckoApp.mAppContext);
|
||||
GeckoAppShell.unregisterGeckoEventListener("Downloads:Done", GeckoApp.mAppContext);
|
||||
|
||||
mFavicons.close();
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.ViewportMetrics;
|
||||
import android.os.*;
|
||||
import android.app.*;
|
||||
@ -78,6 +79,7 @@ public class GeckoEvent {
|
||||
public static final int ACTIVITY_START = 17;
|
||||
public static final int BROADCAST = 19;
|
||||
public static final int VIEWPORT = 20;
|
||||
public static final int TILE_SIZE = 21;
|
||||
|
||||
public static final int IME_COMPOSITION_END = 0;
|
||||
public static final int IME_COMPOSITION_BEGIN = 1;
|
||||
@ -228,6 +230,16 @@ public class GeckoEvent {
|
||||
mP1 = new Point(screenw, screenh);
|
||||
}
|
||||
|
||||
public GeckoEvent(int etype, IntSize size) {
|
||||
if (etype != TILE_SIZE) {
|
||||
mType = INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
mType = etype;
|
||||
mP0 = new Point(size.width, size.height);
|
||||
}
|
||||
|
||||
public GeckoEvent(String subject, String data) {
|
||||
mType = BROADCAST;
|
||||
mCharacters = subject;
|
||||
|
@ -107,6 +107,7 @@ JAVAFILES = \
|
||||
gfx/LayerController.java \
|
||||
gfx/LayerRenderer.java \
|
||||
gfx/LayerView.java \
|
||||
gfx/MultiTileLayer.java \
|
||||
gfx/NinePatchTileLayer.java \
|
||||
gfx/PanningPerfAPI.java \
|
||||
gfx/PlaceholderLayerClient.java \
|
||||
|
@ -43,8 +43,8 @@ import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.LayerClient;
|
||||
import org.mozilla.gecko.gfx.LayerController;
|
||||
import org.mozilla.gecko.gfx.LayerRenderer;
|
||||
import org.mozilla.gecko.gfx.MultiTileLayer;
|
||||
import org.mozilla.gecko.gfx.PointUtils;
|
||||
import org.mozilla.gecko.gfx.SingleTileLayer;
|
||||
import org.mozilla.gecko.gfx.WidgetTileLayer;
|
||||
import org.mozilla.gecko.FloatUtils;
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
@ -53,6 +53,7 @@ import org.mozilla.gecko.GeckoEvent;
|
||||
import org.mozilla.gecko.GeckoEventListener;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
@ -84,6 +85,8 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
|
||||
private CairoImage mCairoImage;
|
||||
|
||||
private static final IntSize TILE_SIZE = new IntSize(256, 256);
|
||||
|
||||
private static final long MIN_VIEWPORT_CHANGE_DELAY = 350L;
|
||||
private long mLastViewportChangeTime;
|
||||
private boolean mPendingViewportAdjust;
|
||||
@ -112,7 +115,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
public int getFormat() { return mFormat; }
|
||||
};
|
||||
|
||||
mTileLayer = new SingleTileLayer(mCairoImage);
|
||||
mTileLayer = new MultiTileLayer(mCairoImage, TILE_SIZE);
|
||||
}
|
||||
|
||||
|
||||
@ -143,6 +146,14 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
GeckoAppShell.registerGeckoEventListener("Viewport:UpdateAndDraw", this);
|
||||
GeckoAppShell.registerGeckoEventListener("Viewport:UpdateLater", this);
|
||||
|
||||
// This needs to happen before a call to sendResizeEventIfNecessary
|
||||
// happens, but only needs to be called once. As that is only called by
|
||||
// the layer controller or this, here is a safe place to do so.
|
||||
if (mTileLayer instanceof MultiTileLayer) {
|
||||
GeckoEvent event = new GeckoEvent(GeckoEvent.TILE_SIZE, TILE_SIZE);
|
||||
GeckoAppShell.sendEventToGecko(event);
|
||||
}
|
||||
|
||||
sendResizeEventIfNecessary();
|
||||
}
|
||||
|
||||
@ -213,8 +224,8 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
mUpdateViewportOnEndDraw = false;
|
||||
Rect rect = new Rect(x, y, x + width, y + height);
|
||||
|
||||
if (mTileLayer instanceof SingleTileLayer)
|
||||
((SingleTileLayer)mTileLayer).invalidate(rect);
|
||||
if (mTileLayer instanceof MultiTileLayer)
|
||||
((MultiTileLayer)mTileLayer).invalidate(rect);
|
||||
} finally {
|
||||
endTransaction(mTileLayer);
|
||||
}
|
||||
@ -228,6 +239,33 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
return null;
|
||||
}
|
||||
|
||||
public void copyPixelsFromMultiTileLayer(Bitmap target) {
|
||||
Canvas c = new Canvas(target);
|
||||
ByteBuffer tileBuffer = mBuffer.slice();
|
||||
int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat) / 8;
|
||||
|
||||
for (int y = 0; y < mBufferSize.height; y += TILE_SIZE.height) {
|
||||
for (int x = 0; x < mBufferSize.width; x += TILE_SIZE.width) {
|
||||
// Calculate tile size
|
||||
IntSize tileSize = new IntSize(Math.min(mBufferSize.width - x, TILE_SIZE.width),
|
||||
Math.min(mBufferSize.height - y, TILE_SIZE.height));
|
||||
|
||||
// Create a Bitmap from this tile
|
||||
Bitmap tile = Bitmap.createBitmap(tileSize.width, tileSize.height,
|
||||
CairoUtils.cairoFormatTobitmapConfig(mFormat));
|
||||
tile.copyPixelsFromBuffer(tileBuffer.asIntBuffer());
|
||||
|
||||
// Copy the tile to the master Bitmap and recycle it
|
||||
c.drawBitmap(tile, x, y, null);
|
||||
tile.recycle();
|
||||
|
||||
// Progress the buffer to the next tile
|
||||
tileBuffer.position(tileSize.getArea() * bpp);
|
||||
tileBuffer = tileBuffer.slice();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Bitmap getBitmap() {
|
||||
// Begin a tile transaction, otherwise the buffer can be destroyed while
|
||||
// we're reading from it.
|
||||
@ -238,7 +276,12 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
try {
|
||||
Bitmap b = Bitmap.createBitmap(mBufferSize.width, mBufferSize.height,
|
||||
CairoUtils.cairoFormatTobitmapConfig(mFormat));
|
||||
b.copyPixelsFromBuffer(mBuffer.asIntBuffer());
|
||||
|
||||
if (mTileLayer instanceof MultiTileLayer)
|
||||
copyPixelsFromMultiTileLayer(b);
|
||||
else
|
||||
b.copyPixelsFromBuffer(mBuffer.asIntBuffer());
|
||||
|
||||
return b;
|
||||
} catch (OutOfMemoryError oom) {
|
||||
Log.w(LOGTAG, "Unable to create bitmap", oom);
|
||||
@ -280,15 +323,25 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
}
|
||||
|
||||
mScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels);
|
||||
int maxSize = getLayerController().getView().getMaxTextureSize();
|
||||
IntSize bufferSize;
|
||||
|
||||
// XXX Introduce tiling to solve this?
|
||||
if (mScreenSize.width > maxSize || mScreenSize.height > maxSize)
|
||||
throw new RuntimeException("Screen size of " + mScreenSize + " larger than maximum texture size of " + maxSize);
|
||||
// Round up depending on layer implementation to remove texture wastage
|
||||
if (mTileLayer instanceof MultiTileLayer) {
|
||||
// Round to the next multiple of the tile size, respecting maximum texture size
|
||||
bufferSize = new IntSize(((mScreenSize.width + LayerController.MIN_BUFFER.width - 1) / TILE_SIZE.width + 1) * TILE_SIZE.width,
|
||||
((mScreenSize.height + LayerController.MIN_BUFFER.height - 1) / TILE_SIZE.height + 1) * TILE_SIZE.height);
|
||||
|
||||
// Round to next power of two until we use NPOT texture support
|
||||
IntSize bufferSize = new IntSize(Math.min(maxSize, IntSize.nextPowerOfTwo(mScreenSize.width + LayerController.MIN_BUFFER.width)),
|
||||
Math.min(maxSize, IntSize.nextPowerOfTwo(mScreenSize.height + LayerController.MIN_BUFFER.height)));
|
||||
} else {
|
||||
int maxSize = getLayerController().getView().getMaxTextureSize();
|
||||
|
||||
// XXX Integrate gralloc/tiling work to circumvent this
|
||||
if (mScreenSize.width > maxSize || mScreenSize.height > maxSize)
|
||||
throw new RuntimeException("Screen size of " + mScreenSize + " larger than maximum texture size of " + maxSize);
|
||||
|
||||
// Round to next power of two until we have NPOT texture support
|
||||
bufferSize = new IntSize(Math.min(maxSize, IntSize.nextPowerOfTwo(mScreenSize.width + LayerController.MIN_BUFFER.width)),
|
||||
Math.min(maxSize, IntSize.nextPowerOfTwo(mScreenSize.height + LayerController.MIN_BUFFER.height)));
|
||||
}
|
||||
|
||||
Log.i(LOGTAG, "Screen-size changed to " + mScreenSize);
|
||||
GeckoEvent event = new GeckoEvent(GeckoEvent.SIZE_CHANGED,
|
||||
|
@ -61,8 +61,11 @@ public abstract class Layer {
|
||||
mResolution = 1.0f;
|
||||
}
|
||||
|
||||
/** Updates the layer. */
|
||||
public final void update(GL10 gl) {
|
||||
/**
|
||||
* Updates the layer. This returns false if there is still work to be done
|
||||
* after this update.
|
||||
*/
|
||||
public final boolean update(GL10 gl, RenderContext context) {
|
||||
if (mTransactionLock.isHeldByCurrentThread()) {
|
||||
throw new RuntimeException("draw() called while transaction lock held by this " +
|
||||
"thread?!");
|
||||
@ -70,11 +73,13 @@ public abstract class Layer {
|
||||
|
||||
if (mTransactionLock.tryLock()) {
|
||||
try {
|
||||
performUpdates(gl);
|
||||
return performUpdates(gl, context);
|
||||
} finally {
|
||||
mTransactionLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Subclasses override this function to draw the layer. */
|
||||
@ -158,9 +163,10 @@ public abstract class Layer {
|
||||
/**
|
||||
* Subclasses may override this method to perform custom layer updates. This will be called
|
||||
* with the transaction lock held. Subclass implementations of this method must call the
|
||||
* superclass implementation.
|
||||
* superclass implementation. Returns false if there is still work to be done after this
|
||||
* update is complete.
|
||||
*/
|
||||
protected void performUpdates(GL10 gl) {
|
||||
protected boolean performUpdates(GL10 gl, RenderContext context) {
|
||||
if (mNewOrigin != null) {
|
||||
mOrigin = mNewOrigin;
|
||||
mNewOrigin = null;
|
||||
@ -169,6 +175,8 @@ public abstract class Layer {
|
||||
mResolution = mNewResolution;
|
||||
mNewResolution = 0.0f;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class RenderContext {
|
||||
|
@ -147,6 +147,8 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
LayerController controller = mView.getController();
|
||||
RenderContext screenContext = createScreenContext();
|
||||
|
||||
boolean updated = true;
|
||||
|
||||
synchronized (controller) {
|
||||
Layer rootLayer = controller.getRoot();
|
||||
RenderContext pageContext = createPageContext();
|
||||
@ -166,12 +168,12 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
mLastPageContext = pageContext;
|
||||
|
||||
/* Update layers. */
|
||||
if (rootLayer != null) rootLayer.update(gl);
|
||||
mShadowLayer.update(gl);
|
||||
mCheckerboardLayer.update(gl);
|
||||
mFrameRateLayer.update(gl);
|
||||
mVertScrollLayer.update(gl);
|
||||
mHorizScrollLayer.update(gl);
|
||||
if (rootLayer != null) updated &= rootLayer.update(gl, pageContext);
|
||||
updated &= mShadowLayer.update(gl, pageContext);
|
||||
updated &= mCheckerboardLayer.update(gl, screenContext);
|
||||
updated &= mFrameRateLayer.update(gl, screenContext);
|
||||
updated &= mVertScrollLayer.update(gl, pageContext);
|
||||
updated &= mHorizScrollLayer.update(gl, pageContext);
|
||||
|
||||
/* Draw the background. */
|
||||
gl.glClearColor(BACKGROUND_COLOR_R, BACKGROUND_COLOR_G, BACKGROUND_COLOR_B, 1.0f);
|
||||
@ -220,6 +222,10 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
// If a layer update requires further work, schedule another redraw
|
||||
if (!updated)
|
||||
mView.requestRender();
|
||||
|
||||
PanningPerfAPI.recordFrameTime();
|
||||
}
|
||||
|
||||
|
284
mobile/android/base/gfx/MultiTileLayer.java
Normal file
284
mobile/android/base/gfx/MultiTileLayer.java
Normal file
@ -0,0 +1,284 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Android code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011-2012
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Lord <chrislord.net@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
package org.mozilla.gecko.gfx;
|
||||
|
||||
import org.mozilla.gecko.gfx.CairoImage;
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.SingleTileLayer;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.Log;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
/**
|
||||
* Encapsulates the logic needed to draw a layer made of multiple tiles.
|
||||
*
|
||||
* TODO: Support repeating.
|
||||
*/
|
||||
public class MultiTileLayer extends Layer {
|
||||
private static final String LOGTAG = "GeckoMultiTileLayer";
|
||||
|
||||
private final CairoImage mImage;
|
||||
private IntSize mTileSize;
|
||||
private IntSize mBufferSize;
|
||||
private final ArrayList<SingleTileLayer> mTiles;
|
||||
|
||||
public MultiTileLayer(CairoImage image, IntSize tileSize) {
|
||||
super();
|
||||
|
||||
mImage = image;
|
||||
mTileSize = tileSize;
|
||||
mBufferSize = new IntSize(0, 0);
|
||||
mTiles = new ArrayList<SingleTileLayer>();
|
||||
}
|
||||
|
||||
public void invalidate(Rect dirtyRect) {
|
||||
if (!inTransaction())
|
||||
throw new RuntimeException("invalidate() is only valid inside a transaction");
|
||||
|
||||
int x = 0, y = 0;
|
||||
IntSize size = getSize();
|
||||
for (SingleTileLayer layer : mTiles) {
|
||||
Rect tileRect = new Rect(x, y, x + mTileSize.width, y + mTileSize.height);
|
||||
|
||||
if (tileRect.intersect(dirtyRect)) {
|
||||
tileRect.offset(-x, -y);
|
||||
layer.invalidate(tileRect);
|
||||
}
|
||||
|
||||
x += mTileSize.width;
|
||||
if (x >= size.width) {
|
||||
x = 0;
|
||||
y += mTileSize.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
for (SingleTileLayer layer : mTiles)
|
||||
layer.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSize getSize() {
|
||||
return mImage.getSize();
|
||||
}
|
||||
|
||||
private void validateTiles() {
|
||||
IntSize size = getSize();
|
||||
|
||||
if (size.equals(mBufferSize))
|
||||
return;
|
||||
|
||||
// Regenerate tiles
|
||||
mTiles.clear();
|
||||
int offset = 0;
|
||||
final int format = mImage.getFormat();
|
||||
final ByteBuffer buffer = mImage.getBuffer().slice();
|
||||
final int bpp = CairoUtils.bitsPerPixelForCairoFormat(format) / 8;
|
||||
for (int y = 0; y < size.height; y += mTileSize.height) {
|
||||
for (int x = 0; x < size.width; x += mTileSize.width) {
|
||||
// Create a CairoImage implementation that returns a
|
||||
// tile from the parent CairoImage. It's assumed that
|
||||
// the tiles are stored in series.
|
||||
final IntSize layerSize =
|
||||
new IntSize(Math.min(mTileSize.width, size.width - x),
|
||||
Math.min(mTileSize.height, size.height - y));
|
||||
final int tileOffset = offset;
|
||||
|
||||
CairoImage subImage = new CairoImage() {
|
||||
@Override
|
||||
public ByteBuffer getBuffer() {
|
||||
// Create a ByteBuffer that shares the data of the original
|
||||
// buffer, but is positioned and limited so that only the
|
||||
// tile data is accessible.
|
||||
buffer.position(tileOffset);
|
||||
ByteBuffer tileBuffer = buffer.slice();
|
||||
tileBuffer.limit(layerSize.getArea() * bpp);
|
||||
|
||||
return tileBuffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSize getSize() {
|
||||
return layerSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFormat() {
|
||||
return format;
|
||||
}
|
||||
};
|
||||
|
||||
mTiles.add(new SingleTileLayer(subImage));
|
||||
offset += layerSize.getArea() * bpp;
|
||||
}
|
||||
}
|
||||
|
||||
// Set tile origins and resolution
|
||||
refreshTileMetrics(getOrigin(), getResolution(), false);
|
||||
|
||||
mBufferSize = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean performUpdates(GL10 gl, RenderContext context) {
|
||||
super.performUpdates(gl, context);
|
||||
|
||||
validateTiles();
|
||||
|
||||
// Iterate over the tiles and decide which ones we'll be drawing
|
||||
int dirtyTiles = 0;
|
||||
boolean screenUpdateDone = false;
|
||||
SingleTileLayer firstDirtyTile = null;
|
||||
for (SingleTileLayer layer : mTiles) {
|
||||
// First do a non-texture update to make sure coordinates are
|
||||
// up-to-date.
|
||||
boolean invalid = layer.getSkipTextureUpdate();
|
||||
layer.setSkipTextureUpdate(true);
|
||||
layer.performUpdates(gl, context);
|
||||
|
||||
RectF layerBounds = layer.getBounds(context, new FloatSize(layer.getSize()));
|
||||
boolean isDirty = layer.isDirty();
|
||||
|
||||
if (isDirty) {
|
||||
if (!RectF.intersects(layerBounds, context.viewport)) {
|
||||
if (firstDirtyTile == null)
|
||||
firstDirtyTile = layer;
|
||||
dirtyTiles ++;
|
||||
invalid = true;
|
||||
} else {
|
||||
// This tile intersects with the screen and is dirty,
|
||||
// update it immediately.
|
||||
layer.setSkipTextureUpdate(false);
|
||||
screenUpdateDone = true;
|
||||
layer.performUpdates(gl, context);
|
||||
invalid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// We use the SkipTextureUpdate flag as a marker of a tile's
|
||||
// validity. This is required, as sometimes layers are drawn
|
||||
// without updating first, and we mustn't draw tiles that have
|
||||
// been marked as invalid that we haven't updated.
|
||||
layer.setSkipTextureUpdate(invalid);
|
||||
}
|
||||
|
||||
// Now if no tiles that intersect with the screen were updated, update
|
||||
// a single tile that doesn't (if there are any). This has the effect
|
||||
// of spreading out non-critical texture upload over time, and smoothing
|
||||
// upload-related hitches.
|
||||
if (!screenUpdateDone && firstDirtyTile != null) {
|
||||
firstDirtyTile.setSkipTextureUpdate(false);
|
||||
firstDirtyTile.performUpdates(gl, context);
|
||||
dirtyTiles --;
|
||||
}
|
||||
|
||||
return (dirtyTiles == 0);
|
||||
}
|
||||
|
||||
private void refreshTileMetrics(Point origin, float resolution, boolean inTransaction) {
|
||||
int x = 0, y = 0;
|
||||
IntSize size = getSize();
|
||||
for (SingleTileLayer layer : mTiles) {
|
||||
if (!inTransaction)
|
||||
layer.beginTransaction(null);
|
||||
|
||||
if (origin != null)
|
||||
layer.setOrigin(new Point(origin.x + x, origin.y + y));
|
||||
if (resolution >= 0.0f)
|
||||
layer.setResolution(resolution);
|
||||
|
||||
if (!inTransaction)
|
||||
layer.endTransaction();
|
||||
|
||||
x += mTileSize.width;
|
||||
if (x >= size.width) {
|
||||
x = 0;
|
||||
y += mTileSize.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrigin(Point newOrigin) {
|
||||
super.setOrigin(newOrigin);
|
||||
refreshTileMetrics(newOrigin, -1, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResolution(float newResolution) {
|
||||
super.setResolution(newResolution);
|
||||
refreshTileMetrics(null, newResolution, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginTransaction(LayerView aView) {
|
||||
super.beginTransaction(aView);
|
||||
|
||||
for (SingleTileLayer layer : mTiles)
|
||||
layer.beginTransaction(aView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endTransaction() {
|
||||
for (SingleTileLayer layer : mTiles)
|
||||
layer.endTransaction();
|
||||
|
||||
super.endTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(RenderContext context) {
|
||||
for (SingleTileLayer layer : mTiles) {
|
||||
// We use the SkipTextureUpdate flag as a validity flag. If it's false,
|
||||
// the contents of this tile are invalid and we shouldn't draw it.
|
||||
if (layer.getSkipTextureUpdate())
|
||||
continue;
|
||||
|
||||
// Avoid work, only draw tiles that intersect with the viewport
|
||||
RectF layerBounds = layer.getBounds(context, new FloatSize(layer.getSize()));
|
||||
if (RectF.intersects(layerBounds, context.viewport))
|
||||
layer.draw(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,12 +59,14 @@ public abstract class TileLayer extends Layer {
|
||||
private final CairoImage mImage;
|
||||
private final boolean mRepeat;
|
||||
private IntSize mSize;
|
||||
private boolean mSkipTextureUpdate;
|
||||
private int[] mTextureIDs;
|
||||
|
||||
public TileLayer(boolean repeat, CairoImage image) {
|
||||
mRepeat = repeat;
|
||||
mImage = image;
|
||||
mSize = new IntSize(0, 0);
|
||||
mSkipTextureUpdate = false;
|
||||
|
||||
IntSize bufferSize = mImage.getSize();
|
||||
mDirtyRect = new Rect();
|
||||
@ -98,6 +100,10 @@ public abstract class TileLayer extends Layer {
|
||||
invalidate(new Rect(0, 0, bufferSize.width, bufferSize.height));
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return mImage.getSize().isPositive() && (mTextureIDs == null || !mDirtyRect.isEmpty());
|
||||
}
|
||||
|
||||
private void validateTexture(GL10 gl) {
|
||||
/* Calculate the ideal texture size. This must be a power of two if
|
||||
* the texture is repeated or OpenGL ES 2.0 isn't supported, as
|
||||
@ -126,16 +132,28 @@ public abstract class TileLayer extends Layer {
|
||||
}
|
||||
}
|
||||
|
||||
/** Tells the tile not to update the texture on the next update. */
|
||||
public void setSkipTextureUpdate(boolean skip) {
|
||||
mSkipTextureUpdate = skip;
|
||||
}
|
||||
|
||||
public boolean getSkipTextureUpdate() {
|
||||
return mSkipTextureUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performUpdates(GL10 gl) {
|
||||
super.performUpdates(gl);
|
||||
protected boolean performUpdates(GL10 gl, RenderContext context) {
|
||||
super.performUpdates(gl, context);
|
||||
|
||||
if (mSkipTextureUpdate)
|
||||
return false;
|
||||
|
||||
// Reallocate the texture if the size has changed
|
||||
validateTexture(gl);
|
||||
|
||||
// Don't do any work if the image has an invalid size.
|
||||
if (!mImage.getSize().isPositive())
|
||||
return;
|
||||
return true;
|
||||
|
||||
// If we haven't allocated a texture, assume the whole region is dirty
|
||||
if (mTextureIDs == null)
|
||||
@ -144,6 +162,8 @@ public abstract class TileLayer extends Layer {
|
||||
uploadDirtyRect(gl, mDirtyRect);
|
||||
|
||||
mDirtyRect.setEmpty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void uploadFullTexture(GL10 gl) {
|
||||
|
@ -77,8 +77,8 @@ public class WidgetTileLayer extends Layer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performUpdates(GL10 gl) {
|
||||
super.performUpdates(gl);
|
||||
protected boolean performUpdates(GL10 gl, RenderContext context) {
|
||||
super.performUpdates(gl, context);
|
||||
|
||||
if (mTextureIDs == null) {
|
||||
mTextureIDs = new int[1];
|
||||
@ -87,6 +87,8 @@ public class WidgetTileLayer extends Layer {
|
||||
|
||||
bindAndSetGLParameters();
|
||||
GeckoAppShell.bindWidgetTexture();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -27,9 +27,7 @@
|
||||
|
||||
<!ENTITY awesomebar_default_text "Enter Search or Address">
|
||||
|
||||
<!ENTITY bookmarks_title "Bookmarks">
|
||||
<!ENTITY bookmark_add "Bookmark">
|
||||
<!ENTITY bookmark_remove "Remove">
|
||||
<!ENTITY bookmark "Bookmark">
|
||||
<!ENTITY bookmark_added "Bookmark added">
|
||||
<!ENTITY bookmark_removed "Bookmark removed">
|
||||
|
||||
@ -72,6 +70,7 @@
|
||||
<!ENTITY quit "Quit">
|
||||
|
||||
<!ENTITY addons "Add-ons">
|
||||
<!ENTITY downloads "Downloads">
|
||||
|
||||
<!ENTITY share "Share">
|
||||
<!ENTITY save_as_pdf "Save as PDF">
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
<item android:id="@+id/bookmark"
|
||||
android:icon="@drawable/ic_menu_bookmark_add"
|
||||
android:title="@string/bookmark_add"/>
|
||||
android:title="@string/bookmark"/>
|
||||
|
||||
<item android:id="@+id/share"
|
||||
android:icon="@drawable/ic_menu_share"
|
||||
@ -33,6 +33,9 @@
|
||||
<item android:id="@+id/addons"
|
||||
android:title="@string/addons"/>
|
||||
|
||||
<item android:id="@+id/downloads"
|
||||
android:title="@string/downloads"/>
|
||||
|
||||
<item android:id="@+id/quit"
|
||||
android:title="@string/quit" />
|
||||
</menu>
|
||||
|
@ -35,9 +35,7 @@
|
||||
<string name="awesomebar_default_text">&awesomebar_default_text;</string>
|
||||
|
||||
<string name="quit">&quit;</string>
|
||||
<string name="bookmarks_title">&bookmarks_title;</string>
|
||||
<string name="bookmark_add">&bookmark_add;</string>
|
||||
<string name="bookmark_remove">&bookmark_remove;</string>
|
||||
<string name="bookmark">&bookmark;</string>
|
||||
<string name="bookmark_added">&bookmark_added;</string>
|
||||
<string name="bookmark_removed">&bookmark_removed;</string>
|
||||
|
||||
@ -80,6 +78,7 @@
|
||||
<string name="forward">&forward;</string>
|
||||
<string name="new_tab">&new_tab;</string>
|
||||
<string name="addons">&addons;</string>
|
||||
<string name="downloads">&downloads;</string>
|
||||
|
||||
<string name="site_settings_title">&site_settings_title;</string>
|
||||
<string name="site_settings_cancel">&site_settings_cancel;</string>
|
||||
|
@ -5,6 +5,7 @@ import com.jayway.android.robotium.solo.Solo;
|
||||
import @ANDROID_PACKAGE_NAME@.*;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.content.Intent;
|
||||
import java.util.HashMap;
|
||||
@ -47,7 +48,7 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
|
||||
mActivity = getActivity();
|
||||
|
||||
// Set up Robotium.solo and Driver objects
|
||||
mSolo = new Solo(getInstrumentation(), getActivity());
|
||||
mSolo = new Solo(getInstrumentation());
|
||||
mDriver = new FennecNativeDriver(mActivity, mSolo);
|
||||
mActions = new FennecNativeActions(mActivity, mSolo, getInstrumentation());
|
||||
mDriver.setLogFile((String)config.get("logfile"));
|
||||
@ -67,30 +68,42 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
protected final Activity getActivityFromClick(Element element) {
|
||||
Instrumentation inst = getInstrumentation();
|
||||
Instrumentation.ActivityMonitor monitor = inst.addMonitor((String)null, null, false);
|
||||
element.click();
|
||||
return inst.waitForMonitor(monitor);
|
||||
}
|
||||
|
||||
protected final void enterUrl(String url) {
|
||||
mActions.waitForGeckoEvent("Gecko:Ready");
|
||||
Element awesomebar = mDriver.findElement("awesome_bar");
|
||||
awesomebar.click();
|
||||
mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
|
||||
Element awesomebar = mDriver.findElement(mActivity, "awesome_bar");
|
||||
Activity awesomeBarActivity = getActivityFromClick(awesomebar);
|
||||
getInstrumentation().waitForIdleSync();
|
||||
|
||||
Element urlbar = mDriver.findElement("awesomebar_text");
|
||||
Element urlbar = mDriver.findElement(awesomeBarActivity, "awesomebar_text");
|
||||
mActions.sendKeys(url);
|
||||
mAsserter.is(urlbar.getText(), url, "Awesomebar URL typed properly");
|
||||
}
|
||||
|
||||
protected final void loadUrl(String url) {
|
||||
enterUrl(url);
|
||||
|
||||
protected final void hitEnterAndWait() {
|
||||
Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.ENTER);
|
||||
// wait for screen to load
|
||||
mActions.waitForGeckoEvent("DOMContentLoaded");
|
||||
contentEventExpecter.blockForEvent();
|
||||
}
|
||||
|
||||
protected final void loadUrl(String url) {
|
||||
enterUrl(url);
|
||||
hitEnterAndWait();
|
||||
}
|
||||
|
||||
protected final void verifyUrl(String url) {
|
||||
Element awesomebar = mDriver.findElement("awesome_bar");
|
||||
Element urlbar = mDriver.findElement("awesomebar_text");
|
||||
awesomebar.click();
|
||||
Element awesomebar = mDriver.findElement(mActivity, "awesome_bar");
|
||||
Activity awesomeBarActivity = getActivityFromClick(awesomebar);
|
||||
getInstrumentation().waitForIdleSync();
|
||||
|
||||
Element urlbar = mDriver.findElement(awesomeBarActivity, "awesomebar_text");
|
||||
mAsserter.is(urlbar.getText(), url, "Awesomebar URL stayed the same");
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,7 @@ public class testBookmark extends BaseTest {
|
||||
|
||||
//Click the top item in the list.
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.DOWN);
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.ENTER);
|
||||
mActions.waitForGeckoEvent("DOMContentLoaded");
|
||||
hitEnterAndWait();
|
||||
|
||||
verifyUrl(URL);
|
||||
|
||||
@ -23,8 +22,8 @@ public class testBookmark extends BaseTest {
|
||||
getInstrumentation().waitForIdleSync();
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.DOWN);
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.DOWN);
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.ENTER);
|
||||
mActions.waitForGeckoEvent("DOMContentLoaded");
|
||||
|
||||
hitEnterAndWait();
|
||||
|
||||
getInstrumentation().waitForIdleSync();
|
||||
//Unfortunately, the item isn't constant so can't be tested.
|
||||
|
@ -2,36 +2,31 @@
|
||||
package @ANDROID_PACKAGE_NAME@.tests;
|
||||
|
||||
import @ANDROID_PACKAGE_NAME@.*;
|
||||
import android.app.Activity;
|
||||
|
||||
public class testNewTab extends BaseTest {
|
||||
public void testNewTab() {
|
||||
// TODO: find a better way to not hardcode this url
|
||||
String url = "http://mochi.test:8888/tests/robocop/robocop_blank_01.html";
|
||||
String url2 = "http://mochi.test:8888/tests/robocop/robocop_blank_02.html";
|
||||
mActions.waitForGeckoEvent("Gecko:Ready");
|
||||
Element tabs = mDriver.findElement("tabs");
|
||||
mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
|
||||
Element tabs = mDriver.findElement(getActivity(), "tabs");
|
||||
// Add one tab
|
||||
tabs.click();
|
||||
Activity awesomeBarActivity = getActivityFromClick(tabs);
|
||||
|
||||
Element urlbar = mDriver.findElement("awesomebar_text");
|
||||
getInstrumentation().waitForIdleSync();
|
||||
Element urlbar = mDriver.findElement(awesomeBarActivity, "awesomebar_text");
|
||||
mActions.sendKeys(url);
|
||||
mAsserter.is(urlbar.getText(), url, "Awesomebar url is fine");
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.ENTER);
|
||||
mActions.waitForGeckoEvent("DOMContentLoaded");
|
||||
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
hitEnterAndWait();
|
||||
|
||||
// See tab count
|
||||
Element tabCount = mDriver.findElement("tabs_count");
|
||||
Element tabCount = mDriver.findElement(getActivity(), "tabs_count");
|
||||
mAsserter.is(tabCount.getText(), "2", "Number of tabs has increased");
|
||||
|
||||
// Click tab list
|
||||
tabs.click();
|
||||
Element addTab = mDriver.findElement("add_tab");
|
||||
Activity tabTray = getActivityFromClick(tabs);
|
||||
Element addTab = mDriver.findElement(tabTray, "add_tab");
|
||||
|
||||
//Add another tab
|
||||
addTab.click();
|
||||
@ -40,8 +35,7 @@ public class testNewTab extends BaseTest {
|
||||
getInstrumentation().waitForIdleSync();
|
||||
mAsserter.is(urlbar.getText(), url2, "URL is still fine");
|
||||
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.ENTER);
|
||||
mActions.waitForGeckoEvent("DOMContentLoaded");
|
||||
hitEnterAndWait();
|
||||
//Check tab count another time.
|
||||
mAsserter.is(tabCount.getText(), "3", "Number of tabs has increased");
|
||||
}
|
||||
|
@ -125,6 +125,7 @@ var Downloads = {
|
||||
},
|
||||
|
||||
observe: function dl_observe(aSubject, aTopic, aData) {
|
||||
let download = aSubject.QueryInterface(Ci.nsIDownload);
|
||||
let msgKey = "";
|
||||
if (aTopic == "dl-start") {
|
||||
msgKey = "alertDownloadsStart";
|
||||
@ -138,12 +139,21 @@ var Downloads = {
|
||||
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertDownloadsToast"), "long");
|
||||
} else if (aTopic == "dl-done") {
|
||||
msgKey = "alertDownloadsDone";
|
||||
|
||||
let message = {
|
||||
gecko: {
|
||||
type: "Downloads:Done",
|
||||
displayName: download.displayName,
|
||||
path: download.targetFile.path,
|
||||
size: download.size,
|
||||
mimeType: download.MIMEInfo ? download.MIMEInfo.type : ""
|
||||
}
|
||||
};
|
||||
sendMessageToJava(message);
|
||||
}
|
||||
|
||||
if (msgKey) {
|
||||
let download = aSubject.QueryInterface(Ci.nsIDownload);
|
||||
if (msgKey)
|
||||
this.showAlert(download, Strings.browser.formatStringFromName(msgKey, [download.displayName], 1));
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: function (aIID) {
|
||||
|
@ -7,9 +7,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
||||
function dump(a) {
|
||||
Cc["@mozilla.org/consoleservice;1"]
|
||||
.getService(Ci.nsIConsoleService)
|
||||
.logStringMessage(a);
|
||||
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(a);
|
||||
}
|
||||
|
||||
function openWindow(aParent, aURL, aTarget, aFeatures, aArgs) {
|
||||
@ -45,10 +43,7 @@ BrowserCLH.prototype = {
|
||||
let urlParam = "about:home";
|
||||
try {
|
||||
urlParam = aCmdLine.handleFlagWithParam("remote", false);
|
||||
} catch (e) {
|
||||
// Optional so not a real error
|
||||
}
|
||||
dump("fs_handle: " + urlParam);
|
||||
} catch (e) { /* Optional */ }
|
||||
|
||||
try {
|
||||
let uri = resolveURIInternal(aCmdLine, urlParam);
|
||||
@ -57,19 +52,14 @@ BrowserCLH.prototype = {
|
||||
|
||||
let browserWin = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
if (browserWin) {
|
||||
browserWin.browserDOMWindow.openURI(uri,
|
||||
null,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_CURRENTWINDOW,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
browserWin.browserDOMWindow.openURI(uri, null, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB, Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
} else {
|
||||
browserWin = openWindow(null, "chrome://browser/content/browser.xul", "_blank", "chrome,dialog=no,all", urlParam);
|
||||
}
|
||||
|
||||
aCmdLine.preventDefault = true;
|
||||
} catch (x) {
|
||||
Cc["@mozilla.org/consoleservice;1"]
|
||||
.getService(Ci.nsIConsoleService)
|
||||
.logStringMessage("fs_handle exception!: " + x);
|
||||
dump("BrowserCLH.handle: " + x);
|
||||
}
|
||||
},
|
||||
|
||||
|
137
netwerk/cache/nsCacheService.cpp
vendored
137
netwerk/cache/nsCacheService.cpp
vendored
@ -75,6 +75,7 @@
|
||||
#include "mozilla/Util.h" // for DebugOnly
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
#include "mozilla/FunctionTimer.h"
|
||||
|
||||
@ -152,6 +153,7 @@ public:
|
||||
, mDiskCacheEnabled(false)
|
||||
, mDiskCacheCapacity(0)
|
||||
, mDiskCacheMaxEntrySize(-1) // -1 means "no limit"
|
||||
, mSmartSizeEnabled(false)
|
||||
, mOfflineCacheEnabled(false)
|
||||
, mOfflineCacheCapacity(0)
|
||||
, mMemoryCacheEnabled(true)
|
||||
@ -175,6 +177,7 @@ public:
|
||||
void SetDiskCacheCapacity(PRInt32);
|
||||
PRInt32 DiskCacheMaxEntrySize() { return mDiskCacheMaxEntrySize; }
|
||||
nsILocalFile * DiskCacheParentDirectory() { return mDiskCacheParentDirectory; }
|
||||
bool SmartSizeEnabled() { return mSmartSizeEnabled; }
|
||||
|
||||
bool OfflineCacheEnabled();
|
||||
PRInt32 OfflineCacheCapacity() { return mOfflineCacheCapacity; }
|
||||
@ -199,6 +202,7 @@ private:
|
||||
PRInt32 mDiskCacheCapacity; // in kilobytes
|
||||
PRInt32 mDiskCacheMaxEntrySize; // in kilobytes
|
||||
nsCOMPtr<nsILocalFile> mDiskCacheParentDirectory;
|
||||
bool mSmartSizeEnabled;
|
||||
|
||||
bool mOfflineCacheEnabled;
|
||||
PRInt32 mOfflineCacheCapacity; // in kilobytes
|
||||
@ -218,6 +222,23 @@ private:
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheProfilePrefObserver, nsIObserver)
|
||||
|
||||
class nsSetDiskSmartSizeCallback : public nsITimerCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Notify(nsITimer* aTimer) {
|
||||
if (nsCacheService::gService) {
|
||||
nsCacheServiceAutoLock autoLock;
|
||||
nsCacheService::gService->SetDiskSmartSize_Locked();
|
||||
nsCacheService::gService->mSmartSizeTimer = nsnull;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsSetDiskSmartSizeCallback, nsITimerCallback)
|
||||
|
||||
// Runnable sent to main thread after the cache IO thread calculates available
|
||||
// disk space, so that there is no race in setting mDiskCacheCapacity.
|
||||
class nsSetSmartSizeEvent: public nsRunnable
|
||||
@ -228,32 +249,27 @@ public:
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsresult rv;
|
||||
NS_ASSERTION(NS_IsMainThread(),
|
||||
"Setting smart size data off the main thread");
|
||||
|
||||
// Main thread may have already called nsCacheService::Shutdown
|
||||
if (!nsCacheService::gService || !nsCacheService::gService->mObserver)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
bool smartSizeEnabled;
|
||||
nsCOMPtr<nsIPrefBranch2> branch = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (!branch) {
|
||||
NS_WARNING("Failed to get pref service!");
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
// ensure smart sizing wasn't switched off while event was pending
|
||||
rv = branch->GetBoolPref(DISK_CACHE_SMART_SIZE_ENABLED_PREF,
|
||||
&smartSizeEnabled);
|
||||
if (NS_FAILED(rv))
|
||||
smartSizeEnabled = false;
|
||||
if (smartSizeEnabled) {
|
||||
nsCacheService::SetDiskCacheCapacity(mSmartSize);
|
||||
rv = branch->SetIntPref(DISK_CACHE_SMART_SIZE_PREF, mSmartSize);
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("Failed to set smart size pref");
|
||||
}
|
||||
return rv;
|
||||
|
||||
// Ensure smart sizing wasn't switched off while event was pending.
|
||||
// It is safe to access the observer without the lock since we are
|
||||
// on the main thread and the value changes only on the main thread.
|
||||
if (!nsCacheService::gService->mObserver->SmartSizeEnabled())
|
||||
return NS_OK;
|
||||
|
||||
nsCacheService::SetDiskCacheCapacity(mSmartSize);
|
||||
|
||||
nsCOMPtr<nsIPrefBranch2> ps = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (!ps ||
|
||||
NS_FAILED(ps->SetIntPref(DISK_CACHE_SMART_SIZE_PREF, mSmartSize)))
|
||||
NS_WARNING("Failed to set smart size pref");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -445,13 +461,12 @@ nsCacheProfilePrefObserver::Observe(nsISupports * subject,
|
||||
// Update the cache capacity when smart sizing is turned on/off
|
||||
} else if (!strcmp(DISK_CACHE_SMART_SIZE_ENABLED_PREF, data.get())) {
|
||||
// Is the update because smartsizing was turned on, or off?
|
||||
bool smartSizeEnabled;
|
||||
rv = branch->GetBoolPref(DISK_CACHE_SMART_SIZE_ENABLED_PREF,
|
||||
&smartSizeEnabled);
|
||||
&mSmartSizeEnabled);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
PRInt32 newCapacity = 0;
|
||||
if (smartSizeEnabled) {
|
||||
if (mSmartSizeEnabled) {
|
||||
nsCacheService::SetDiskSmartSize();
|
||||
} else {
|
||||
// Smart sizing switched off: use user specified size
|
||||
@ -671,21 +686,22 @@ nsCacheProfilePrefObserver::PermittedToSmartSize(nsIPrefBranch* branch, bool
|
||||
// of 50 MB, then keep user's value. Otherwise use smart sizing.
|
||||
rv = branch->GetIntPref(DISK_CACHE_CAPACITY_PREF, &oldCapacity);
|
||||
if (oldCapacity < PRE_GECKO_2_0_DEFAULT_CACHE_SIZE) {
|
||||
branch->SetBoolPref(DISK_CACHE_SMART_SIZE_ENABLED_PREF,
|
||||
false);
|
||||
return false;
|
||||
mSmartSizeEnabled = false;
|
||||
branch->SetBoolPref(DISK_CACHE_SMART_SIZE_ENABLED_PREF,
|
||||
mSmartSizeEnabled);
|
||||
return mSmartSizeEnabled;
|
||||
}
|
||||
}
|
||||
// Set manual setting to MAX cache size as starting val for any
|
||||
// adjustment by user: (bug 559942 comment 65)
|
||||
branch->SetIntPref(DISK_CACHE_CAPACITY_PREF, MAX_CACHE_SIZE);
|
||||
}
|
||||
bool smartSizeEnabled;
|
||||
|
||||
rv = branch->GetBoolPref(DISK_CACHE_SMART_SIZE_ENABLED_PREF,
|
||||
&smartSizeEnabled);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
return !!smartSizeEnabled;
|
||||
&mSmartSizeEnabled);
|
||||
if (NS_FAILED(rv))
|
||||
mSmartSizeEnabled = false;
|
||||
return mSmartSizeEnabled;
|
||||
}
|
||||
|
||||
|
||||
@ -758,20 +774,12 @@ nsCacheProfilePrefObserver::ReadPrefs(nsIPrefBranch* branch)
|
||||
if (PermittedToSmartSize(branch, firstSmartSizeRun)) {
|
||||
// Avoid evictions: use previous cache size until smart size event
|
||||
// updates mDiskCacheCapacity
|
||||
if (!firstSmartSizeRun) {
|
||||
PRInt32 oldSmartSize;
|
||||
rv = branch->GetIntPref(DISK_CACHE_SMART_SIZE_PREF,
|
||||
&oldSmartSize);
|
||||
mDiskCacheCapacity = oldSmartSize;
|
||||
} else {
|
||||
PRInt32 oldCapacity;
|
||||
rv = branch->GetIntPref(DISK_CACHE_CAPACITY_PREF, &oldCapacity);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mDiskCacheCapacity = oldCapacity;
|
||||
} else {
|
||||
mDiskCacheCapacity = DEFAULT_CACHE_SIZE;
|
||||
}
|
||||
}
|
||||
rv = branch->GetIntPref(firstSmartSizeRun ?
|
||||
DISK_CACHE_CAPACITY_PREF :
|
||||
DISK_CACHE_SMART_SIZE_PREF,
|
||||
&mDiskCacheCapacity);
|
||||
if (NS_FAILED(rv))
|
||||
mDiskCacheCapacity = DEFAULT_CACHE_SIZE;
|
||||
}
|
||||
|
||||
if (firstSmartSizeRun) {
|
||||
@ -1142,6 +1150,11 @@ nsCacheService::Shutdown()
|
||||
ClearDoomList();
|
||||
ClearActiveEntries();
|
||||
|
||||
if (mSmartSizeTimer) {
|
||||
mSmartSizeTimer->Cancel();
|
||||
mSmartSizeTimer = nsnull;
|
||||
}
|
||||
|
||||
// Make sure to wait for any pending cache-operations before
|
||||
// proceeding with destructive actions (bug #620660)
|
||||
(void) SyncWithCacheIOThread();
|
||||
@ -1447,7 +1460,22 @@ nsCacheService::CreateDiskDevice()
|
||||
mDiskDevice = nsnull;
|
||||
}
|
||||
|
||||
SetDiskSmartSize_Locked(true);
|
||||
// Disk device is usually created during the startup. Delay smart size
|
||||
// calculation to avoid possible massive IO caused by eviction of entries
|
||||
// in case the new smart size is smaller than current cache usage.
|
||||
if (!mSmartSizeTimer) {
|
||||
mSmartSizeTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = mSmartSizeTimer->InitWithCallback(new nsSetDiskSmartSizeCallback(),
|
||||
1000*60*3,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to post smart size timer");
|
||||
mSmartSizeTimer = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -2652,11 +2680,11 @@ nsCacheService::SetDiskSmartSize()
|
||||
|
||||
if (!gService) return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return gService->SetDiskSmartSize_Locked(false);
|
||||
return gService->SetDiskSmartSize_Locked();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheService::SetDiskSmartSize_Locked(bool checkPref)
|
||||
nsCacheService::SetDiskSmartSize_Locked()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
@ -2666,17 +2694,8 @@ nsCacheService::SetDiskSmartSize_Locked(bool checkPref)
|
||||
if (!mDiskDevice)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
if (checkPref) {
|
||||
nsCOMPtr<nsIPrefBranch2> branch = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (!branch) return NS_ERROR_FAILURE;
|
||||
|
||||
bool smartSizeEnabled;
|
||||
rv = branch->GetBoolPref(DISK_CACHE_SMART_SIZE_ENABLED_PREF,
|
||||
&smartSizeEnabled);
|
||||
|
||||
if (NS_FAILED(rv) || !smartSizeEnabled)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if (!mObserver->SmartSizeEnabled())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsAutoString cachePath;
|
||||
rv = mObserver->DiskCacheParentDirectory()->GetPath(cachePath);
|
||||
|
5
netwerk/cache/nsCacheService.h
vendored
5
netwerk/cache/nsCacheService.h
vendored
@ -63,6 +63,7 @@ class nsDiskCacheDevice;
|
||||
class nsMemoryCacheDevice;
|
||||
class nsOfflineCacheDevice;
|
||||
class nsCacheServiceAutoLock;
|
||||
class nsITimer;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
@ -196,6 +197,7 @@ private:
|
||||
friend class nsProcessRequestEvent;
|
||||
friend class nsSetSmartSizeEvent;
|
||||
friend class nsBlockOnCacheThreadEvent;
|
||||
friend class nsSetDiskSmartSizeCallback;
|
||||
|
||||
/**
|
||||
* Internal Methods
|
||||
@ -264,7 +266,7 @@ private:
|
||||
void LogCacheStatistics();
|
||||
#endif
|
||||
|
||||
nsresult SetDiskSmartSize_Locked(bool checkPref);
|
||||
nsresult SetDiskSmartSize_Locked();
|
||||
|
||||
/**
|
||||
* Data Members
|
||||
@ -280,6 +282,7 @@ private:
|
||||
nsCOMPtr<nsIThread> mCacheIOThread;
|
||||
|
||||
nsTArray<nsISupports*> mDoomedObjects;
|
||||
nsCOMPtr<nsITimer> mSmartSizeTimer;
|
||||
|
||||
bool mInitialized;
|
||||
|
||||
|
26
netwerk/cache/nsDiskCacheDevice.cpp
vendored
26
netwerk/cache/nsDiskCacheDevice.cpp
vendored
@ -118,6 +118,22 @@ private:
|
||||
nsDiskCacheBinding *mBinding;
|
||||
};
|
||||
|
||||
class nsEvictDiskCacheEntriesEvent : public nsRunnable {
|
||||
public:
|
||||
nsEvictDiskCacheEntriesEvent(nsDiskCacheDevice *device)
|
||||
: mDevice(device) {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsCacheServiceAutoLock lock;
|
||||
mDevice->EvictDiskCacheEntries(mDevice->mCacheCapacity);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsDiskCacheDevice *mDevice;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* nsDiskCacheEvictor
|
||||
*
|
||||
@ -1120,8 +1136,14 @@ nsDiskCacheDevice::SetCapacity(PRUint32 capacity)
|
||||
// Units are KiB's
|
||||
mCacheCapacity = capacity;
|
||||
if (Initialized()) {
|
||||
// start evicting entries if the new size is smaller!
|
||||
EvictDiskCacheEntries(mCacheCapacity);
|
||||
if (NS_IsMainThread()) {
|
||||
// Do not evict entries on the main thread
|
||||
nsCacheService::DispatchToCacheIOThread(
|
||||
new nsEvictDiskCacheEntriesEvent(this));
|
||||
} else {
|
||||
// start evicting entries if the new size is smaller!
|
||||
EvictDiskCacheEntries(mCacheCapacity);
|
||||
}
|
||||
}
|
||||
// Let cache map know of the new capacity
|
||||
mCacheMap.NotifyCapacityChange(capacity);
|
||||
|
1
netwerk/cache/nsDiskCacheDevice.h
vendored
1
netwerk/cache/nsDiskCacheDevice.h
vendored
@ -107,6 +107,7 @@ public:
|
||||
|
||||
private:
|
||||
friend class nsDiskCacheDeviceDeactivateEntryEvent;
|
||||
friend class nsEvictDiskCacheEntriesEvent;
|
||||
/**
|
||||
* Private methods
|
||||
*/
|
||||
|
@ -1017,7 +1017,7 @@ nsCookieService::TryInitDB(bool aRecreateDB)
|
||||
// Use write-ahead-logging for performance. We cap the autocheckpoint limit at
|
||||
// 16 pages (around 500KB).
|
||||
mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"PRAGMA journal_mode = WAL"));
|
||||
MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA journal_mode = WAL"));
|
||||
mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"PRAGMA wal_autocheckpoint = 16"));
|
||||
|
||||
|
@ -113,6 +113,8 @@ nsHttpPipeline::~nsHttpPipeline()
|
||||
// make sure we aren't still holding onto any transactions!
|
||||
Close(NS_ERROR_ABORT);
|
||||
|
||||
NS_IF_RELEASE(mConnection);
|
||||
|
||||
if (mPushBackBuf)
|
||||
free(mPushBackBuf);
|
||||
}
|
||||
@ -125,7 +127,7 @@ nsHttpPipeline::AddTransaction(nsAHttpTransaction *trans)
|
||||
NS_ADDREF(trans);
|
||||
mRequestQ.AppendElement(trans);
|
||||
|
||||
if (mConnection) {
|
||||
if (mConnection && !mClosed) {
|
||||
trans->SetConnection(this);
|
||||
|
||||
if (mRequestQ.Length() == 1)
|
||||
@ -700,10 +702,6 @@ nsHttpPipeline::Close(nsresult reason)
|
||||
mResponseQ.Clear();
|
||||
}
|
||||
|
||||
// we must no longer reference the connection! This needs to come
|
||||
// after we've closed all our transactions, since they might want
|
||||
// connection info as they close.
|
||||
NS_IF_RELEASE(mConnection);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -192,4 +192,9 @@ protected:
|
||||
nsCOMPtr<mozIStorageStatement> mStatement;
|
||||
};
|
||||
|
||||
// Use this to make queries uniquely identifiable in telemetry
|
||||
// statistics, especially PRAGMAs. We don't include __LINE__ so that
|
||||
// queries are stable in the face of source code changes.
|
||||
#define MOZ_STORAGE_UNIQUIFY_QUERY_STR "/* " __FILE__ " */ "
|
||||
|
||||
#endif /* MOZSTORAGEHELPER_H */
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "mozIStorageAsyncStatement.h"
|
||||
#include "mozIStoragePendingStatement.h"
|
||||
#include "mozIStorageError.h"
|
||||
#include "mozStorageHelper.h"
|
||||
|
||||
#define OBSERVER_TOPIC_IDLE_DAILY "idle-daily"
|
||||
#define OBSERVER_TOPIC_XPCOM_SHUTDOWN "xpcom-shutdown"
|
||||
@ -221,7 +222,7 @@ Vacuumer::execute()
|
||||
{
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"PRAGMA page_size"
|
||||
MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA page_size"
|
||||
), getter_AddRefs(stmt));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
bool hasResult;
|
||||
@ -240,7 +241,7 @@ Vacuumer::execute()
|
||||
{
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"PRAGMA journal_mode"
|
||||
MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA journal_mode"
|
||||
), getter_AddRefs(stmt));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
bool hasResult;
|
||||
@ -300,7 +301,7 @@ Vacuumer::execute()
|
||||
if (canOptimizePageSize) {
|
||||
nsCOMPtr<mozIStorageAsyncStatement> pageSizeStmt;
|
||||
rv = mDBConn->CreateAsyncStatement(nsPrintfCString(
|
||||
"PRAGMA page_size = %ld", expectedPageSize
|
||||
MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA page_size = %ld", expectedPageSize
|
||||
), getter_AddRefs(pageSizeStmt));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
nsCOMPtr<BaseCallback> callback = new BaseCallback();
|
||||
|
@ -70,6 +70,7 @@
|
||||
#include "StorageBaseStatementInternal.h"
|
||||
#include "SQLCollations.h"
|
||||
#include "FileSystemModule.h"
|
||||
#include "mozStorageHelper.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#include "prprf.h"
|
||||
@ -650,14 +651,17 @@ Connection::initialize(nsIFile *aDatabaseFile,
|
||||
// the database has just been created, otherwise, if the database does not
|
||||
// use WAL journal mode, a VACUUM operation will updated its page_size.
|
||||
PRInt64 pageSize = DEFAULT_PAGE_SIZE;
|
||||
nsCAutoString pageSizeQuery("PRAGMA page_size = ");
|
||||
nsCAutoString pageSizeQuery(MOZ_STORAGE_UNIQUIFY_QUERY_STR
|
||||
"PRAGMA page_size = ");
|
||||
pageSizeQuery.AppendInt(pageSize);
|
||||
rv = ExecuteSimpleSQL(pageSizeQuery);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get the current page_size, since it may differ from the specified value.
|
||||
sqlite3_stmt *stmt;
|
||||
srv = prepareStatement(NS_LITERAL_CSTRING("PRAGMA page_size"), &stmt);
|
||||
NS_NAMED_LITERAL_CSTRING(pragma_page_size,
|
||||
MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA page_size");
|
||||
srv = prepareStatement(pragma_page_size, &stmt);
|
||||
if (srv == SQLITE_OK) {
|
||||
if (SQLITE_ROW == stepStatement(stmt)) {
|
||||
pageSize = ::sqlite3_column_int64(stmt, 0);
|
||||
@ -668,7 +672,8 @@ Connection::initialize(nsIFile *aDatabaseFile,
|
||||
// Setting the cache_size forces the database open, verifying if it is valid
|
||||
// or corrupt. So this is executed regardless it being actually needed.
|
||||
// The cache_size is calculated from the actual page_size, to save memory.
|
||||
nsCAutoString cacheSizeQuery("PRAGMA cache_size = ");
|
||||
nsCAutoString cacheSizeQuery(MOZ_STORAGE_UNIQUIFY_QUERY_STR
|
||||
"PRAGMA cache_size = ");
|
||||
cacheSizeQuery.AppendInt(NS_MIN(DEFAULT_CACHE_SIZE_PAGES,
|
||||
PRInt32(MAX_CACHE_SIZE_BYTES / pageSize)));
|
||||
srv = ::sqlite3_exec(mDBConn, cacheSizeQuery.get(), NULL, NULL, NULL);
|
||||
|
@ -798,11 +798,12 @@ toolbar#nav-bar {
|
||||
self.automation.log.warning("TEST-UNEXPECTED-FAIL | invalid setup: missing mochikit extension")
|
||||
return None
|
||||
|
||||
# Support Firefox (browser) and SeaMonkey (navigator).
|
||||
# Support Firefox (browser), B2G (shell) and SeaMonkey (navigator).
|
||||
chrome = ""
|
||||
if options.browserChrome or options.chrome or options.a11y:
|
||||
chrome += """
|
||||
overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul
|
||||
overlay chrome://browser/content/shell.xul chrome://mochikit/content/browser-test-overlay.xul
|
||||
overlay chrome://navigator/content/navigator.xul chrome://mochikit/content/browser-test-overlay.xul
|
||||
"""
|
||||
|
||||
|
@ -280,6 +280,7 @@ class MochiRemote(Mochitest):
|
||||
def buildProfile(self, options):
|
||||
manifest = Mochitest.buildProfile(self, options)
|
||||
self.localProfile = options.profilePath
|
||||
self._dm.removeDir(self.remoteProfile)
|
||||
if self._dm.pushDir(options.profilePath, self.remoteProfile) == None:
|
||||
raise devicemanager.FileError("Unable to copy profile to device.")
|
||||
|
||||
|
@ -233,7 +233,8 @@ SetJournalMode(nsCOMPtr<mozIStorageConnection>& aDBConn,
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> statement;
|
||||
nsCAutoString query("PRAGMA journal_mode = ");
|
||||
nsCAutoString query(MOZ_STORAGE_UNIQUIFY_QUERY_STR
|
||||
"PRAGMA journal_mode = ");
|
||||
query.Append(journalMode);
|
||||
aDBConn->CreateStatement(query, getter_AddRefs(statement));
|
||||
NS_ENSURE_TRUE(statement, JOURNAL_DELETE);
|
||||
@ -551,7 +552,7 @@ Database::InitSchema(bool* aDatabaseMigrated)
|
||||
// database file already existed with a different page size.
|
||||
nsCOMPtr<mozIStorageStatement> statement;
|
||||
nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"PRAGMA page_size"
|
||||
MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA page_size"
|
||||
), getter_AddRefs(statement));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
bool hasResult = false;
|
||||
@ -563,7 +564,7 @@ Database::InitSchema(bool* aDatabaseMigrated)
|
||||
|
||||
// Ensure that temp tables are held in memory, not on disk.
|
||||
nsresult rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"PRAGMA temp_store = MEMORY"));
|
||||
MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA temp_store = MEMORY"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get the current database size. Due to chunked growth we have to use
|
||||
@ -593,7 +594,8 @@ Database::InitSchema(bool* aDatabaseMigrated)
|
||||
// Set the number of cached pages.
|
||||
// We don't use PRAGMA default_cache_size, since the database could be moved
|
||||
// among different devices and the value would adapt accordingly.
|
||||
nsCAutoString cacheSizePragma("PRAGMA cache_size = ");
|
||||
nsCAutoString cacheSizePragma(MOZ_STORAGE_UNIQUIFY_QUERY_STR
|
||||
"PRAGMA cache_size = ");
|
||||
cacheSizePragma.AppendInt(cacheSize / mDBPageSize);
|
||||
rv = mMainConn->ExecuteSimpleSQL(cacheSizePragma);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -908,11 +908,11 @@ let PlacesDBUtils = {
|
||||
}
|
||||
},
|
||||
|
||||
PLACES_DATABASE_PAGESIZE_B: "PRAGMA page_size",
|
||||
PLACES_DATABASE_PAGESIZE_B: "PRAGMA page_size /* PlacesDBUtils.jsm PAGESIZE_B */",
|
||||
|
||||
PLACES_DATABASE_SIZE_PER_PAGE_B: function() {
|
||||
// Cannot use the filesize here, due to chunked growth.
|
||||
let stmt = DBConn.createStatement("PRAGMA page_size");
|
||||
let stmt = DBConn.createStatement("PRAGMA page_size /* PlacesDBUtils.jsm SIZE_PER_PAGE_B */");
|
||||
stmt.executeStep();
|
||||
let pageSize = stmt.row.page_size;
|
||||
stmt.finalize();
|
||||
|
@ -3126,7 +3126,8 @@ nsUrlClassifierDBServiceWorker::SetCacheSize(
|
||||
NS_ASSERTION(hasResult, "Should always be able to get page size from sqlite");
|
||||
PRUint32 pageSize = mGetPageSizeStatement->AsInt32(0);
|
||||
PRUint32 cachePages = aCacheSize / pageSize;
|
||||
nsCAutoString cacheSizePragma("PRAGMA cache_size=");
|
||||
nsCAutoString cacheSizePragma(MOZ_STORAGE_UNIQUIFY_QUERY_STR
|
||||
"PRAGMA cache_size=");
|
||||
cacheSizePragma.AppendInt(cachePages);
|
||||
rv = aConnection->ExecuteSimpleSQL(cacheSizePragma);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -3413,7 +3414,7 @@ nsUrlClassifierDBServiceWorker::OpenDb()
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = connection->CreateStatement
|
||||
(NS_LITERAL_CSTRING("PRAGMA page_size"),
|
||||
(NS_LITERAL_CSTRING(MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA page_size"),
|
||||
getter_AddRefs(mGetPageSizeStatement));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -1279,8 +1279,20 @@
|
||||
var self = this;
|
||||
this.muteButton.addEventListener("command", function() { self.toggleMute(); }, false);
|
||||
this.playButton.addEventListener("command", function() { self.togglePause(); }, false);
|
||||
this.controlsSpacer.addEventListener("click", function(e) { if (e.button == 0 && !self.hasError()) { self.togglePause(); } }, false);
|
||||
this.fullscreenButton.addEventListener("command", function() { self.toggleFullscreen(); }, false );
|
||||
|
||||
this.controlsSpacer.addEventListener("click", function spacerClickHandler(e) {
|
||||
if (e.button != 0 || self.hasError())
|
||||
return;
|
||||
// Read defaultPrevented asynchronously, since Web content
|
||||
// may want to consume the "click" event but will only
|
||||
// receive it after us (bug 693014).
|
||||
setTimeout(function togglePauseCallback() {
|
||||
if (!e.defaultPrevented)
|
||||
self.togglePause();
|
||||
}, 0);
|
||||
}, false);
|
||||
|
||||
if (!this.isAudioOnly) {
|
||||
this.muteButton.addEventListener("mouseover", function(e) { self.onVolumeMouseInOut(e); }, false);
|
||||
this.muteButton.addEventListener("mouseout", function(e) { self.onVolumeMouseInOut(e); }, false);
|
||||
|
@ -823,9 +823,10 @@ var gViewController = {
|
||||
isEnabled: function(aAddon) {
|
||||
return !!aAddon && (gViewController.currentViewObj != gDetailView);
|
||||
},
|
||||
doCommand: function(aAddon) {
|
||||
doCommand: function(aAddon, aScrollToPreferences) {
|
||||
gViewController.loadView("addons://detail/" +
|
||||
encodeURIComponent(aAddon.id));
|
||||
encodeURIComponent(aAddon.id) +
|
||||
(aScrollToPreferences ? "/preferences" : ""));
|
||||
}
|
||||
},
|
||||
|
||||
@ -964,7 +965,7 @@ var gViewController = {
|
||||
},
|
||||
doCommand: function(aAddon) {
|
||||
if (aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE) {
|
||||
gViewController.commands.cmd_showItemDetails.doCommand(aAddon);
|
||||
gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true);
|
||||
return;
|
||||
}
|
||||
var optionsURL = aAddon.optionsURL;
|
||||
@ -2565,7 +2566,7 @@ var gDetailView = {
|
||||
}
|
||||
},
|
||||
|
||||
_updateView: function(aAddon, aIsRemote) {
|
||||
_updateView: function(aAddon, aIsRemote, aScrollToPreferences) {
|
||||
this._updatePrefs.addObserver("", this, false);
|
||||
this.clearLoading();
|
||||
|
||||
@ -2738,7 +2739,7 @@ var gDetailView = {
|
||||
}
|
||||
}
|
||||
|
||||
this.fillSettingsRows();
|
||||
this.fillSettingsRows(aScrollToPreferences);
|
||||
|
||||
this.updateState();
|
||||
|
||||
@ -2747,6 +2748,13 @@ var gDetailView = {
|
||||
},
|
||||
|
||||
show: function(aAddonId, aRequest) {
|
||||
let index = aAddonId.indexOf("/preferences");
|
||||
let scrollToPreferences = false;
|
||||
if (index >= 0) {
|
||||
aAddonId = aAddonId.substring(0, index);
|
||||
scrollToPreferences = true;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
this._loadingTimer = setTimeout(function() {
|
||||
self.node.setAttribute("loading-extended", true);
|
||||
@ -2759,7 +2767,7 @@ var gDetailView = {
|
||||
return;
|
||||
|
||||
if (aAddon) {
|
||||
self._updateView(aAddon, false);
|
||||
self._updateView(aAddon, false, scrollToPreferences);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2878,7 +2886,7 @@ var gDetailView = {
|
||||
rows.removeChild(rows.lastChild);
|
||||
},
|
||||
|
||||
fillSettingsRows: function () {
|
||||
fillSettingsRows: function (aScrollToPreferences) {
|
||||
this.emptySettingsRows();
|
||||
if (this._addon.optionsType != AddonManager.OPTIONS_TYPE_INLINE)
|
||||
return;
|
||||
@ -2952,11 +2960,31 @@ var gDetailView = {
|
||||
if (firstSetting)
|
||||
firstSetting.clientTop;
|
||||
Services.obs.notifyObservers(document, "addon-options-displayed", gDetailView._addon.id);
|
||||
if (aScrollToPreferences)
|
||||
gDetailView.scrollToPreferencesRows();
|
||||
}, false);
|
||||
} else {
|
||||
if (firstSetting)
|
||||
firstSetting.clientTop;
|
||||
Services.obs.notifyObservers(document, "addon-options-displayed", this._addon.id);
|
||||
if (aScrollToPreferences)
|
||||
gDetailView.scrollToPreferencesRows();
|
||||
}
|
||||
},
|
||||
|
||||
scrollToPreferencesRows: function() {
|
||||
// We find this row, rather than remembering it from above,
|
||||
// in case it has been changed by the observers.
|
||||
let firstRow = gDetailView.node.querySelector('setting[first-row="true"]');
|
||||
if (firstRow) {
|
||||
let top = firstRow.boxObject.y;
|
||||
top -= parseInt(window.getComputedStyle(firstRow, null).getPropertyValue("margin-top"));
|
||||
|
||||
let detailViewBoxObject = gDetailView.node.boxObject;
|
||||
top -= detailViewBoxObject.y;
|
||||
|
||||
detailViewBoxObject.QueryInterface(Ci.nsIScrollBoxObject);
|
||||
detailViewBoxObject.scrollTo(0, top);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -23,6 +23,9 @@ var observer = {
|
||||
var setting = aSubject.querySelector("rows > setting[first-row] ~ setting");
|
||||
var input = gManagerWindow.document.getAnonymousElementByAttribute(setting, "class", "setting-label");
|
||||
isnot(input, null, "XBL binding should be applied");
|
||||
|
||||
// Add some extra height to the scrolling pane to ensure that it needs to scroll when appropriate.
|
||||
gManagerWindow.document.getElementById("detail-controls").style.marginBottom = "1000px";
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -39,6 +42,17 @@ function installAddon(aCallback) {
|
||||
}, "application/x-xpinstall");
|
||||
}
|
||||
|
||||
function checkScrolling(aShouldHaveScrolled) {
|
||||
var detailView = gManagerWindow.document.getElementById("detail-view");
|
||||
var boxObject = detailView.boxObject;
|
||||
boxObject.QueryInterface(Ci.nsIScrollBoxObject);
|
||||
ok(detailView.scrollHeight > boxObject.height, "Page should require scrolling");
|
||||
if (aShouldHaveScrolled)
|
||||
isnot(detailView.scrollTop, 0, "Page should have scrolled");
|
||||
else
|
||||
is(detailView.scrollTop, 0, "Page should not have scrolled");
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
@ -147,14 +161,15 @@ add_test(function() {
|
||||
|
||||
wait_for_view_load(gManagerWindow, function() {
|
||||
is(observer.lastData, "inlinesettings1@tests.mozilla.org", "Observer notification should have fired");
|
||||
is(gManagerWindow.gViewController.currentViewId,
|
||||
"addons://detail/inlinesettings1%40tests.mozilla.org/preferences",
|
||||
"Current view should scroll to preferences");
|
||||
checkScrolling(true);
|
||||
|
||||
var grid = gManagerWindow.document.getElementById("detail-grid");
|
||||
var settings = grid.querySelectorAll("rows > setting");
|
||||
is(settings.length, SETTINGS_ROWS, "Grid should have settings children");
|
||||
|
||||
// Force bindings to apply
|
||||
settings[0].clientTop;
|
||||
|
||||
ok(settings[0].hasAttribute("first-row"), "First visible row should have first-row attribute");
|
||||
Services.prefs.setBoolPref("extensions.inlinesettings1.bool", false);
|
||||
var input = gManagerWindow.document.getAnonymousElementByAttribute(settings[0], "anonid", "input");
|
||||
@ -288,9 +303,6 @@ add_test(function() {
|
||||
var settings = grid.querySelectorAll("rows > setting");
|
||||
is(settings.length, 4, "Grid should have settings children");
|
||||
|
||||
// Force bindings to apply
|
||||
settings[0].clientTop;
|
||||
|
||||
ok(settings[0].hasAttribute("first-row"), "First visible row should have first-row attribute");
|
||||
Services.prefs.setBoolPref("extensions.inlinesettings3.radioBool", false);
|
||||
var radios = settings[0].getElementsByTagName("radio");
|
||||
@ -354,9 +366,6 @@ add_test(function() {
|
||||
var settings = grid.querySelectorAll("rows > setting");
|
||||
is(settings.length, 5, "Grid should have settings children");
|
||||
|
||||
// Force bindings to apply
|
||||
settings[0].clientTop;
|
||||
|
||||
var node = settings[0];
|
||||
node = settings[0];
|
||||
is_element_hidden(node, "Unsupported settings should not be visible");
|
||||
@ -439,10 +448,15 @@ add_test(function() {
|
||||
var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
|
||||
addon.parentNode.ensureElementIsVisible(addon);
|
||||
|
||||
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
|
||||
var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
|
||||
EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
|
||||
|
||||
wait_for_view_load(gManagerWindow, function() {
|
||||
is(gManagerWindow.gViewController.currentViewId,
|
||||
"addons://detail/inlinesettings1%40tests.mozilla.org",
|
||||
"Current view should not scroll to preferences");
|
||||
checkScrolling(false);
|
||||
|
||||
var grid = gManagerWindow.document.getElementById("detail-grid");
|
||||
var settings = grid.querySelectorAll("rows > setting");
|
||||
is(settings.length, SETTINGS_ROWS, "Grid should have settings children");
|
||||
|
@ -66,7 +66,7 @@
|
||||
min-height: 41px;
|
||||
}
|
||||
|
||||
@media all and (max-width: 600px) {
|
||||
@media (max-width: 600px) {
|
||||
.global-warning-text {
|
||||
display: none;
|
||||
}
|
||||
@ -206,7 +206,7 @@
|
||||
}
|
||||
|
||||
/* Maximize the size of the viewport when the window is small */
|
||||
@media all and (max-width: 800px) {
|
||||
@media (max-width: 800px) {
|
||||
.category-name {
|
||||
display: none;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@
|
||||
border-bottom: 1px solid rgba(50, 65, 92, 0.4);
|
||||
}
|
||||
|
||||
@media all and (max-width: 600px) {
|
||||
@media (max-width: 600px) {
|
||||
.global-warning-text {
|
||||
display: none;
|
||||
}
|
||||
@ -239,7 +239,7 @@
|
||||
}
|
||||
|
||||
/* Maximize the size of the viewport when the window is small */
|
||||
@media all and (max-width: 800px) {
|
||||
@media (max-width: 800px) {
|
||||
.category-name {
|
||||
display: none;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ html|html {
|
||||
}
|
||||
|
||||
%ifdef WINSTRIPE_AERO
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
*|*:root {
|
||||
color: #000;
|
||||
background-color: #CCD9EA;
|
||||
@ -72,7 +72,7 @@ html|html {
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-compositor) {
|
||||
@media (-moz-windows-compositor) {
|
||||
*|*:root {
|
||||
color: #000;
|
||||
/* Blame shorlander for this monstrosity. */
|
||||
@ -117,7 +117,7 @@ html|html {
|
||||
}
|
||||
|
||||
%ifdef WINSTRIPE_AERO
|
||||
@media all and (-moz-windows-compositor) {
|
||||
@media (-moz-windows-compositor) {
|
||||
/* Buttons */
|
||||
*|button,
|
||||
menulist,
|
||||
|
@ -1,6 +1,6 @@
|
||||
%include menu.css
|
||||
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
menubar > menu:-moz-lwtheme {
|
||||
-moz-appearance: menuitem;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ menuitem[_moz-menuactive="true"][disabled="true"],
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-classic) {
|
||||
@media (-moz-windows-classic) {
|
||||
menu[disabled="true"],
|
||||
menubar > menu[disabled="true"][_moz-menuactive="true"],
|
||||
menuitem[disabled="true"],
|
||||
|
@ -70,7 +70,7 @@ notification[type="critical"] .messageImage {
|
||||
%ifdef XP_WIN
|
||||
/*
|
||||
XXX: apply styles to all themes until bug 509642 is fixed
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
*/
|
||||
.popup-notification-menubutton[type="menu-button"] {
|
||||
-moz-appearance: none;
|
||||
|
@ -131,7 +131,7 @@ panel[type="arrow"] {
|
||||
%endif
|
||||
|
||||
%ifdef XP_WIN
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
panel[type="arrow"][side="top"],
|
||||
panel[type="arrow"][side="bottom"] {
|
||||
margin-left: -25px;
|
||||
|
@ -1,6 +1,6 @@
|
||||
%include toolbarbutton.css
|
||||
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
toolbarbutton:-moz-lwtheme:not([disabled="true"]) {
|
||||
color: inherit;
|
||||
text-shadow: inherit;
|
||||
|
@ -96,7 +96,7 @@ toolbarbutton[disabled="true"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-classic) {
|
||||
@media (-moz-windows-classic) {
|
||||
toolbarbutton[disabled="true"] {
|
||||
color: ThreeDShadow;
|
||||
text-shadow: 1px 1px ThreeDHighlight;
|
||||
@ -113,7 +113,7 @@ toolbarbutton[checked="true"]:not([disabled="true"]) {
|
||||
color: ButtonText;
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
toolbarbutton:-moz-lwtheme {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
%include downloads.css
|
||||
|
||||
@media all and (-moz-windows-compositor) {
|
||||
@media (-moz-windows-compositor) {
|
||||
#downloadManager {
|
||||
-moz-appearance: -moz-win-glass;
|
||||
background: transparent;
|
||||
|
@ -10,7 +10,7 @@
|
||||
color: -moz-DialogText;
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-compositor) {
|
||||
@media (-moz-windows-compositor) {
|
||||
#genericAbout {
|
||||
-moz-appearance: -moz-win-glass;
|
||||
background: transparent;
|
||||
|
@ -87,7 +87,7 @@
|
||||
border-bottom: 1px solid #CAD4E0;
|
||||
}
|
||||
|
||||
@media all and (max-width: 600px) {
|
||||
@media (max-width: 600px) {
|
||||
.global-warning-text {
|
||||
display: none;
|
||||
}
|
||||
@ -251,7 +251,7 @@
|
||||
}
|
||||
|
||||
/* Maximize the size of the viewport when the window is small */
|
||||
@media all and (max-width: 800px) {
|
||||
@media (max-width: 800px) {
|
||||
.category-name {
|
||||
display: none;
|
||||
}
|
||||
@ -319,7 +319,7 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
#header-search {
|
||||
-moz-appearance: none;
|
||||
border: 1px solid rgba(0, 0, 0, 0.32);
|
||||
|
@ -207,7 +207,7 @@
|
||||
}
|
||||
|
||||
%ifdef WINSTRIPE_AERO
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
#footer {
|
||||
background-color: #f1f5fb;
|
||||
box-shadow: 0px 1px 2px rgb(204,214,234) inset;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:set ts=4 sw=4 sts=4 et cindent: */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -59,9 +59,14 @@ public:
|
||||
|
||||
SharedLibrary& operator=(const SharedLibrary& aEntry)
|
||||
{
|
||||
// Gracefully handle self assignment
|
||||
if (this == &aEntry) return *this;
|
||||
|
||||
mStart = aEntry.mStart;
|
||||
mEnd = aEntry.mEnd;
|
||||
mOffset = aEntry.mOffset;
|
||||
if (mName)
|
||||
free(mName);
|
||||
mName = strdup(aEntry.mName);
|
||||
return *this;
|
||||
}
|
||||
|
@ -408,6 +408,10 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj)
|
||||
mType = jenv->GetIntField(jobj, jTypeField);
|
||||
|
||||
switch (mType) {
|
||||
case TILE_SIZE:
|
||||
ReadP0Field(jenv);
|
||||
break;
|
||||
|
||||
case SIZE_CHANGED:
|
||||
ReadP0Field(jenv);
|
||||
ReadP1Field(jenv);
|
||||
|
@ -532,6 +532,7 @@ public:
|
||||
ACTIVITY_START = 17,
|
||||
BROADCAST = 19,
|
||||
VIEWPORT = 20,
|
||||
TILE_SIZE = 21,
|
||||
dummy_java_enum_list_end
|
||||
};
|
||||
|
||||
|
@ -87,6 +87,7 @@ NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
|
||||
|
||||
// The dimensions of the current android view
|
||||
static gfxIntSize gAndroidBounds = gfxIntSize(0, 0);
|
||||
static gfxIntSize gAndroidTileSize = gfxIntSize(0, 0);
|
||||
static gfxIntSize gAndroidScreenBounds;
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
@ -981,6 +982,12 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
|
||||
win->OnDraw(ae);
|
||||
break;
|
||||
|
||||
case AndroidGeckoEvent::TILE_SIZE: {
|
||||
gAndroidTileSize.width = ae->P0().x;
|
||||
gAndroidTileSize.height = ae->P0().y;
|
||||
break;
|
||||
}
|
||||
|
||||
case AndroidGeckoEvent::IME_EVENT:
|
||||
win->UserActivity();
|
||||
if (win->mFocus) {
|
||||
@ -1196,42 +1203,56 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
|
||||
sDirectTexture->Reallocate(gAndroidBounds.width, gAndroidBounds.height);
|
||||
}
|
||||
|
||||
sDirectTexture->Lock(AndroidGraphicBuffer::UsageSoftwareWrite, &bits);
|
||||
sDirectTexture->Lock(AndroidGraphicBuffer::UsageSoftwareWrite, ae->Rect(), &bits);
|
||||
} else {
|
||||
bits = client.LockBufferBits();
|
||||
}
|
||||
if (!bits) {
|
||||
ALOG("### Failed to lock buffer");
|
||||
|
||||
if (sHasDirectTexture) {
|
||||
sDirectTexture->Unlock();
|
||||
} else {
|
||||
client.UnlockBuffer();
|
||||
}
|
||||
} else {
|
||||
nsRefPtr<gfxImageSurface> targetSurface =
|
||||
new gfxImageSurface(bits, gfxIntSize(gAndroidBounds.width, gAndroidBounds.height), gAndroidBounds.width * 2,
|
||||
gfxASurface::ImageFormatRGB16_565);
|
||||
if (targetSurface->CairoStatus()) {
|
||||
ALOG("### Failed to create a valid surface from the bitmap");
|
||||
} else {
|
||||
if (sHasDirectTexture) {
|
||||
// XXX: lock only the dirty rect above and pass it in here
|
||||
DrawTo(targetSurface);
|
||||
} else {
|
||||
DrawTo(targetSurface, ae->Rect());
|
||||
}
|
||||
// If tile size is 0,0, we assume we only have a single tile
|
||||
int tileWidth = (gAndroidTileSize.width > 0) ? gAndroidTileSize.width : gAndroidBounds.width;
|
||||
int tileHeight = (gAndroidTileSize.height > 0) ? gAndroidTileSize.height : gAndroidBounds.height;
|
||||
|
||||
if (metadataProvider) {
|
||||
metadataProvider->GetDrawMetadata(metadata);
|
||||
bool drawSuccess = true;
|
||||
int offset = 0;
|
||||
|
||||
for (int y = 0; y < gAndroidBounds.height; y += tileHeight) {
|
||||
for (int x = 0; x < gAndroidBounds.width; x += tileWidth) {
|
||||
int width = NS_MIN(tileWidth, gAndroidBounds.width - x);
|
||||
int height = NS_MIN(tileHeight, gAndroidBounds.height - y);
|
||||
|
||||
nsRefPtr<gfxImageSurface> targetSurface =
|
||||
new gfxImageSurface(bits + offset,
|
||||
gfxIntSize(width, height),
|
||||
width * 2,
|
||||
gfxASurface::ImageFormatRGB16_565);
|
||||
|
||||
offset += width * height * 2;
|
||||
|
||||
if (targetSurface->CairoStatus()) {
|
||||
ALOG("### Failed to create a valid surface from the bitmap");
|
||||
drawSuccess = false;
|
||||
break;
|
||||
} else {
|
||||
targetSurface->SetDeviceOffset(gfxPoint(-x, -y));
|
||||
DrawTo(targetSurface, ae->Rect());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sHasDirectTexture) {
|
||||
sDirectTexture->Unlock();
|
||||
} else {
|
||||
client.UnlockBuffer();
|
||||
|
||||
// Don't fill in the draw metadata on an unsuccessful draw
|
||||
if (drawSuccess && metadataProvider) {
|
||||
metadataProvider->GetDrawMetadata(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
if (sHasDirectTexture) {
|
||||
sDirectTexture->Unlock();
|
||||
} else {
|
||||
client.UnlockBuffer();
|
||||
}
|
||||
|
||||
client.EndDrawing(ae->Rect(), metadata);
|
||||
return;
|
||||
#endif
|
||||
|
@ -191,12 +191,25 @@ nsWindow::Show(bool aState)
|
||||
if (mWindowType == eWindowType_invisible)
|
||||
return NS_OK;
|
||||
|
||||
if (mVisible == aState)
|
||||
return NS_OK;
|
||||
|
||||
mVisible = aState;
|
||||
if (!IS_TOPLEVEL())
|
||||
return mParent ? mParent->Show(aState) : NS_OK;
|
||||
|
||||
if (aState)
|
||||
if (aState) {
|
||||
BringToTop();
|
||||
} else {
|
||||
for (unsigned int i = 0; i < sTopWindows.Length(); i++) {
|
||||
nsWindow *win = sTopWindows[i];
|
||||
if (!win->mVisible)
|
||||
continue;
|
||||
|
||||
win->BringToTop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -210,8 +223,8 @@ nsWindow::IsVisible(bool & aState)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::ConstrainPosition(bool aAllowSlop,
|
||||
PRInt32 *aX,
|
||||
PRInt32 *aY)
|
||||
PRInt32 *aX,
|
||||
PRInt32 *aY)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
@ -287,10 +300,8 @@ nsWindow::Invalidate(const nsIntRect &aRect,
|
||||
nsWindow *parent = mParent;
|
||||
while (parent && parent != sTopWindows[0])
|
||||
parent = parent->mParent;
|
||||
if (parent != sTopWindows[0]) {
|
||||
LOG(" parent isn't top window, bailing");
|
||||
if (parent != sTopWindows[0])
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mDirtyRegion.Or(mDirtyRegion, aRect);
|
||||
gWindowToRedraw = this;
|
||||
@ -350,13 +361,13 @@ NS_IMETHODIMP_(void)
|
||||
nsWindow::SetInputContext(const InputContext& aContext,
|
||||
const InputContextAction& aAction)
|
||||
{
|
||||
mInputContext = aContext;
|
||||
mInputContext = aContext;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(InputContext)
|
||||
nsWindow::GetInputContext()
|
||||
{
|
||||
return mInputContext;
|
||||
return mInputContext;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -429,5 +440,6 @@ nsWindow::BringToTop()
|
||||
|
||||
nsGUIEvent event(true, NS_ACTIVATE, this);
|
||||
(*mEventCallback)(&event);
|
||||
Update();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user