зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to birch.
This commit is contained in:
Коммит
bf49d89795
|
@ -0,0 +1,292 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
The `lang/functional` module provides functional helper methods. A lot of these
|
||||
functions implement APIs from Jeremy Ashkenas's [underscore.js](http://underscorejs.org)
|
||||
and all credits go to him and his contributors.
|
||||
|
||||
<api name="method">
|
||||
@function
|
||||
Takes a function and returns a method associated with an object.
|
||||
When the method is invoked on an instance of the object, the original
|
||||
function is called. It is passed the object instance (i.e. `this`) as
|
||||
the first parameter, followed by any parameters passed into the method.
|
||||
|
||||
let { method } = require("sdk/lang/functional");
|
||||
let myNumber = {
|
||||
times: method(times),
|
||||
add: method(add),
|
||||
number: 0
|
||||
};
|
||||
|
||||
function times (target, x) { return target.number *= x; }
|
||||
function add (target, x) { return target.number += x; }
|
||||
|
||||
console.log(myNumber.number); // 0
|
||||
myNumber.add(10); // 10
|
||||
myNumber.times(2); // 20
|
||||
myNumber.add(3); // 23
|
||||
|
||||
@param lambda {function}
|
||||
The function to be wrapped and returned.
|
||||
|
||||
@returns {function}
|
||||
The wrapped `lambda`.
|
||||
</api>
|
||||
|
||||
<api name="defer">
|
||||
@function
|
||||
Takes a function and returns a wrapped version of the function. Calling the
|
||||
wrapped version will call the original function during the next event loop.
|
||||
This is similar to calling [setTimeout](modules/sdk/timers.html#setTimeout(callback%2C ms)) with no
|
||||
wait (i.e. `setTimeout(function () { ... }, 0)`), except that the wrapped function
|
||||
may be reused and does not need to be repeated each time. This also enables you
|
||||
to use these functions as event listeners.
|
||||
|
||||
let { defer } = require("sdk/lang/functional");
|
||||
let fn = defer(function myEvent (event, value) {
|
||||
console.log(event + " : " + value);
|
||||
});
|
||||
|
||||
fn("click", "#home");
|
||||
console.log("done");
|
||||
|
||||
// This will print 'done' before 'click : #home' since
|
||||
// we deferred the execution of the wrapped `myEvent`
|
||||
// function, making it non-blocking and executing on the
|
||||
// next event loop
|
||||
|
||||
@param fn {function}
|
||||
The function to be deferred.
|
||||
|
||||
@returns {function}
|
||||
The new, deferred function.
|
||||
</api>
|
||||
|
||||
<api name="remit">
|
||||
@function
|
||||
An alias for [defer](modules/sdk/lang/functional.html#defer(fn)).
|
||||
</api>
|
||||
|
||||
<api name="invoke">
|
||||
@function
|
||||
Invokes `callee`, passing `params` as an argument and `self` as `this`.
|
||||
Returns the value that is returned by `callee`.
|
||||
|
||||
let { invoke } = require("sdk/lang/functional");
|
||||
|
||||
invoke(sum, [1,2,3,4,5], null); // 15
|
||||
|
||||
function sum () {
|
||||
return Array.slice(arguments).reduce(function (a, b) {
|
||||
return a + b;
|
||||
});
|
||||
}
|
||||
|
||||
@param callee {function}
|
||||
Function to invoke.
|
||||
@param params {Array}
|
||||
Parameters to be passed into `callee`.
|
||||
@param self {mixed}
|
||||
Object to be passed as the `this` context to `callee`.
|
||||
@returns {mixed}
|
||||
Returns the return value of `callee`.
|
||||
</api>
|
||||
|
||||
<api name="curry">
|
||||
@function
|
||||
[Curries](http://en.wikipedia.org/wiki/Currying) the given function with the arguments given.
|
||||
|
||||
let { curry } = require("sdk/lang/functional");
|
||||
let add = function add (x, y) { return x + y; }
|
||||
let addOne = curry(add, 1);
|
||||
|
||||
addOne(5); // 6
|
||||
addOne(10); // 11
|
||||
curry(add, addOne(20))(2); // 23
|
||||
|
||||
@param fn {function}
|
||||
Function to be curried.
|
||||
|
||||
@param arguments... {mixed}
|
||||
Additional arguments
|
||||
|
||||
@returns {function}
|
||||
The curried function.
|
||||
</api>
|
||||
|
||||
<api name="compose">
|
||||
@function
|
||||
Returns the [composition](http://en.wikipedia.org/wiki/Function_composition_(computer_science)) of a list of functions, where each function consumes the
|
||||
return value of the function that follows. In math terms, composing the functions
|
||||
`f()`, `g()`, and `h()` produces `f(g(h()))`.
|
||||
|
||||
let { compose } = require("sdk/lang/functional");
|
||||
|
||||
let welcome = compose(exclaim, greet);
|
||||
|
||||
welcome('moe'); // "hi: moe!";
|
||||
|
||||
function greet (name) { return "hi: " + name; }
|
||||
function exclaim (statement) { return statement + "!"; }
|
||||
|
||||
@param fn... {function}
|
||||
Takes a variable number of functions as arguments and composes them from right to left.
|
||||
|
||||
@returns {function}
|
||||
The composed function.
|
||||
</api>
|
||||
|
||||
<api name="wrap">
|
||||
@function
|
||||
Returns the first function passed as an argument to the second,
|
||||
allowing you to adjust arguments, run code before and after, and
|
||||
conditionally execute the original function.
|
||||
|
||||
let { wrap } = require("sdk/lang/functional");
|
||||
|
||||
let wrappedHello = wrap(hello, function (fn, name) {
|
||||
return "before, " + fn(name) + "after";
|
||||
});
|
||||
|
||||
wrappedHello("moe"); // "before, hello: moe, after"
|
||||
|
||||
function hello (name) { return "hello: " + name; }
|
||||
|
||||
@param fn {function}
|
||||
The function to be passed into the `wrapper` function.
|
||||
|
||||
@param wrapper {function}
|
||||
The function that is called when the return function is executed,
|
||||
taking the wrapped `fn` as the first parameter.
|
||||
|
||||
@returns {function}
|
||||
A function which, when called, executes `wrapper` with `fn` as the first parameter,
|
||||
and passes in any additional parameters to the `wrapper` function.
|
||||
</api>
|
||||
|
||||
<api name="identity">
|
||||
@function
|
||||
Returns the same value that is used as the argument. In math: f(x) = x.
|
||||
|
||||
let { identity } = require("sdk/lang/functional");
|
||||
let x = 5;
|
||||
identity(x); // 5
|
||||
|
||||
@param value {mixed}
|
||||
The value to be returned.
|
||||
|
||||
@returns {mixed}
|
||||
The value that was originally passed in.
|
||||
</api>
|
||||
|
||||
<api name="memoize">
|
||||
@function
|
||||
[Memoizes](http://en.wikipedia.org/wiki/Memoization) a given function by caching
|
||||
the computed result. Useful for speeding up slow-running computations. If
|
||||
passed an optional `hashFunction`, it will be used to compute the hash key for
|
||||
storing the result, based on the arguments to the original function. The
|
||||
default `hashFunction` just uses the first argument to the memoized function as
|
||||
the key.
|
||||
|
||||
let { memoize } = require("sdk/lang/functional");
|
||||
|
||||
let memoizedFn = memoize(primeFactorization);
|
||||
|
||||
memoizedFn(50); // Returns [2, 5, 5], had to compute
|
||||
memoizedFn(100); // Returns [2, 2, 5, 5], had to compute
|
||||
memoizedFn(50); // Returns [2, 5, 5] again, but pulled from cache
|
||||
|
||||
function primeFactorization (x) {
|
||||
// Some tricky stuff
|
||||
}
|
||||
|
||||
// We can also use a hash function to compute a different
|
||||
// hash value. In this example, we'll fabricate a function
|
||||
// that takes a string of first and last names that
|
||||
// somehow computes the lineage of that name. Our hash
|
||||
// function will just parse the last name, as our naive
|
||||
// implementation assumes that they will share the same lineage
|
||||
|
||||
let getLineage = memoize(function (name) {
|
||||
// computes lineage
|
||||
return data;
|
||||
}, hasher);
|
||||
|
||||
// Hashing function takes a string of first and last name
|
||||
// and returns the last name.
|
||||
function hasher (input) {
|
||||
return input.split(" ")[1];
|
||||
}
|
||||
|
||||
getLineage("homer simpson"); // Computes and returns information for "simpson"
|
||||
getLineage("lisa simpson"); // Returns cached for "simpson"
|
||||
|
||||
@param fn {function}
|
||||
The function that becomes memoized.
|
||||
|
||||
@param hasher {function}
|
||||
An optional function that takes the memoized function's parameter and returns
|
||||
a hash key for storing the result.
|
||||
|
||||
@returns {function}
|
||||
The memoized version of `fn`.
|
||||
</api>
|
||||
|
||||
<api name="delay">
|
||||
@function
|
||||
Much like `setTimeout`, `delay` invokes a function after waiting a set number of
|
||||
milliseconds. If you pass additional, optional, arguments, they will be forwarded
|
||||
on to the function when it is invoked.
|
||||
|
||||
let { delay } = require("sdk/lang/functional");
|
||||
|
||||
delay(printAdd, 2000, 5, 10);
|
||||
|
||||
// Prints "5+10=15" in two seconds (2000ms)
|
||||
function printAdd (a, b) { console.log(a + "+" + b + "=" + (a+b)); }
|
||||
|
||||
@param fn {function}
|
||||
A function to be delayed.
|
||||
|
||||
@param ms {number}
|
||||
Number of milliseconds to delay the execution of `fn`.
|
||||
|
||||
@param arguments {mixed}
|
||||
Additional arguments to pass to `fn` upon execution
|
||||
</api>
|
||||
|
||||
<api name="once">
|
||||
@function
|
||||
Creates a version of the input function that can only be called one time.
|
||||
Repeated calls to the modified function will have no effect, returning
|
||||
the value from the original call. Useful for initialization functions, instead
|
||||
of having to set a boolean flag and checking it later.
|
||||
|
||||
let { once } = require("sdk/lang/functional");
|
||||
let setup = once(function (env) {
|
||||
// initializing important things
|
||||
console.log("successfully initialized " + env);
|
||||
return 1; // Assume success and return 1
|
||||
});
|
||||
|
||||
setup('dev'); // returns 1
|
||||
// prints "successfully initialized dev"
|
||||
|
||||
// Future attempts to call this function just return the cached
|
||||
// value that was returned previously
|
||||
setup('production'); // Returns 1
|
||||
// No print message is displayed since the function isn't executed
|
||||
|
||||
@param fn {function}
|
||||
The function that will be executed only once inside the once wrapper.
|
||||
|
||||
@returns {function}
|
||||
The wrapped `fn` that can only be executed once.
|
||||
</api>
|
||||
|
||||
<api name="cache">
|
||||
@function
|
||||
An alias for [once](modules/sdk/lang/functional.html#once(fn)).
|
||||
</api>
|
|
@ -421,7 +421,73 @@ Creates a panel.
|
|||
The width of the panel in pixels. Optional.
|
||||
@prop [height] {number}
|
||||
The height of the panel in pixels. Optional.
|
||||
@prop [focus] {boolean}
|
||||
@prop [position] {object}
|
||||
The position of the panel.
|
||||
Ignored if the panel is opened by a widget.
|
||||
|
||||
You can set as value an object that has one or more of the following
|
||||
properites: `top`, `right`, `bottom` and `left`. Their values are expressed
|
||||
in pixels. Any other properties will be ignored.
|
||||
|
||||
The default alignment is centered, so for example panel can be displayed in
|
||||
the center of the bottom corner by leaving off vertical axis:
|
||||
|
||||
// Show the panel to the centered horizontally and aligned to the bottom
|
||||
// of the content area
|
||||
require("sdk/panel").Panel({
|
||||
position: {
|
||||
bottom: 0
|
||||
}
|
||||
}).show();
|
||||
|
||||
// Show the panel to the centered vertically and aligned to the left o
|
||||
// the content area
|
||||
require("sdk/panel").Panel({
|
||||
position: {
|
||||
left: 0
|
||||
}
|
||||
}).show();
|
||||
|
||||
// Centered panel, default behavior
|
||||
require("sdk/panel").Panel({}).show();
|
||||
|
||||
In the same way of their CSS counterpart, setting both `top` and `bottom`,
|
||||
or `left` and `right`, will results in calculated the `height` and `width`:
|
||||
|
||||
// Show the panel centered horizontally, that is distant 40px
|
||||
// from the top and 100px from the bottom.
|
||||
require("sdk/panel").Panel({
|
||||
position: {
|
||||
top: 40,
|
||||
bottom: 100
|
||||
}
|
||||
}).show();
|
||||
|
||||
Set implicitly `height` in this example, will makes the panel ignore the
|
||||
`bottom` property, as the CSS homonym properties does:
|
||||
|
||||
// Show the panel centered horizontally, that is distant 40px from the top
|
||||
// and has 400px as height
|
||||
require("sdk/panel").Panel({
|
||||
position: {
|
||||
top: 40,
|
||||
bottom: 100,
|
||||
},
|
||||
height: 400
|
||||
}).show();
|
||||
|
||||
// This is equivalent to:
|
||||
|
||||
require("panel").Panel({
|
||||
position {
|
||||
top: 40
|
||||
},
|
||||
height: 400
|
||||
}).show();
|
||||
|
||||
The same principle is applied for `width`, `left` and `right`.
|
||||
|
||||
@prop [focus=true] {boolean}
|
||||
Set to `false` to prevent taking the focus away when the panel is shown.
|
||||
Only turn this off if necessary, to prevent accessibility issue.
|
||||
Optional, default to `true`.
|
||||
|
@ -575,6 +641,22 @@ The message to send. Must be stringifiable to JSON.
|
|||
<api name="show">
|
||||
@method
|
||||
Displays the panel.
|
||||
|
||||
If the `options` argument is given, it will be shallow merged with the options
|
||||
provided in the constructor: the `options` passed in the `show` method takes
|
||||
the precedence.
|
||||
It's useful for temporary changes, without touching the default values.
|
||||
|
||||
@param options {object}
|
||||
Showing options for the panel, with the following keys:
|
||||
@prop [width] {number}
|
||||
The width of the panel in pixels. Optional.
|
||||
@prop [height] {number}
|
||||
The height of the panel in pixels. Optional.
|
||||
@prop [position] {object}
|
||||
The position of the panel. Optional. See [Panel's options](./modules/sdk/panel.html#Panel%28options%29) for further details.
|
||||
@prop [focus=true] {boolean}
|
||||
Set to `false` to prevent taking the focus away when the panel is shown.
|
||||
</api>
|
||||
|
||||
<api name="hide">
|
||||
|
|
|
@ -48,7 +48,7 @@ interface to listen for and log all topic notifications:
|
|||
observerService.addObserver(this, this.topic, false);
|
||||
},
|
||||
unregister: function() {
|
||||
addObserver.removeObserver(this, this.topic);
|
||||
observerService.removeObserver(this, this.topic);
|
||||
},
|
||||
observe: function observe(subject, topic, data) {
|
||||
console.log('star observer:', subject, topic, data);
|
||||
|
|
|
@ -79,6 +79,22 @@ to support private browsing, refer to the
|
|||
@returns {nsIBaseWindow}
|
||||
</api>
|
||||
|
||||
<api name="getToplevelWindow">
|
||||
@function
|
||||
Returns the toplevel
|
||||
[`nsIDOMWindow`](https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIDOMWindow)
|
||||
for the given child [`nsIDOMWindow`](https://developer.mozilla.org/en/nsIDOMWindow):
|
||||
|
||||
var { Ci } = require('chrome');
|
||||
var utils = require('sdk/window/utils');
|
||||
var browserWindow = utils.getMostRecentBrowserWindow();
|
||||
var window = browserWindow.content; // `window` object for the current webpage
|
||||
utils.getToplevelWindw(window) == browserWindow // => true
|
||||
|
||||
@param window {nsIDOMWindow}
|
||||
@returns {nsIDOMWindow}
|
||||
</api>
|
||||
|
||||
<api name="getWindowDocShell">
|
||||
@function
|
||||
Returns the
|
||||
|
|
|
@ -130,7 +130,7 @@ const WorkerSandbox = EventEmitter.compose({
|
|||
|
||||
// Instantiate trusted code in another Sandbox in order to prevent content
|
||||
// script from messing with standard classes used by proxy and API code.
|
||||
let apiSandbox = sandbox(window, { wantXrays: true });
|
||||
let apiSandbox = sandbox(window, { wantXrays: true, sameZoneAs: window });
|
||||
apiSandbox.console = console;
|
||||
|
||||
// Build content proxies only if the document has a non-system principal
|
||||
|
@ -148,7 +148,8 @@ const WorkerSandbox = EventEmitter.compose({
|
|||
// have access to all standard globals (window, document, ...)
|
||||
let content = this._sandbox = sandbox(window, {
|
||||
sandboxPrototype: proto,
|
||||
wantXrays: true
|
||||
wantXrays: true,
|
||||
sameZoneAs: window
|
||||
});
|
||||
// We have to ensure that window.top and window.parent are the exact same
|
||||
// object than window object, i.e. the sandbox global object. But not
|
||||
|
|
|
@ -105,7 +105,7 @@ function defer(prototype) {
|
|||
// `null` promise is not resolved yet.
|
||||
var result = null;
|
||||
|
||||
prototype = (prototype || prototype === null) ? prototype : Object.prototype
|
||||
prototype = (prototype || prototype === null) ? prototype : Object.prototype;
|
||||
|
||||
// Create an object implementing promise API.
|
||||
var promise = Object.create(prototype, {
|
||||
|
@ -137,7 +137,7 @@ function defer(prototype) {
|
|||
}
|
||||
catch(error) {
|
||||
if (exports._reportErrors && typeof(console) === 'object')
|
||||
console.error(error)
|
||||
console.error(error);
|
||||
deferred.resolve(rejected(error));
|
||||
}
|
||||
}
|
||||
|
@ -244,8 +244,8 @@ var promised = (function() {
|
|||
// slower property accesses and unnecessary closure creations on each
|
||||
// call of this popular function.
|
||||
|
||||
var call = Function.call
|
||||
var concat = Array.prototype.concat
|
||||
var call = Function.call;
|
||||
var concat = Array.prototype.concat;
|
||||
|
||||
// Utility function that does following:
|
||||
// execute([ f, self, args...]) => f.apply(self, args)
|
||||
|
@ -256,9 +256,9 @@ var promised = (function() {
|
|||
function promisedConcat(promises, unknown) {
|
||||
return promises.then(function(values) {
|
||||
return resolve(unknown).then(function(value) {
|
||||
return values.concat([ value ])
|
||||
})
|
||||
})
|
||||
return values.concat([ value ]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return function promised(f, prototype) {
|
||||
|
@ -280,10 +280,10 @@ var promised = (function() {
|
|||
// reduce it via `promisedConcat` to get promised array of fulfillments
|
||||
reduce(promisedConcat, resolve([], prototype)).
|
||||
// finally map that to promise of `f.apply(this, args...)`
|
||||
then(execute)
|
||||
}
|
||||
then(execute);
|
||||
};
|
||||
}
|
||||
})()
|
||||
})();
|
||||
exports.promised = promised;
|
||||
|
||||
var all = promised(Array);
|
||||
|
|
|
@ -96,6 +96,9 @@ exports.validateOptions = function validateOptions(options, requirements) {
|
|||
optsVal = req.map(optsVal);
|
||||
}
|
||||
catch (err) {
|
||||
if (err instanceof RequirementError)
|
||||
throw err;
|
||||
|
||||
mapThrew = true;
|
||||
}
|
||||
}
|
||||
|
@ -108,12 +111,12 @@ exports.validateOptions = function validateOptions(options, requirements) {
|
|||
}
|
||||
});
|
||||
if (req.is.indexOf(getTypeOf(optsVal)) < 0)
|
||||
throw requirementError(key, req);
|
||||
throw new RequirementError(key, req);
|
||||
}
|
||||
if (req.ok && !req.ok(optsVal))
|
||||
throw requirementError(key, req);
|
||||
throw new RequirementError(key, req);
|
||||
|
||||
if (keyInOpts || (req.map && !mapThrew))
|
||||
if (keyInOpts || (req.map && !mapThrew && optsVal !== undefined))
|
||||
validatedOptions[key] = optsVal;
|
||||
}
|
||||
|
||||
|
@ -145,8 +148,11 @@ let getTypeOf = exports.getTypeOf = function getTypeOf(val) {
|
|||
return typ;
|
||||
}
|
||||
|
||||
// Returns a new Error with a nice message.
|
||||
function requirementError(key, requirement) {
|
||||
function RequirementError(key, requirement) {
|
||||
Error.call(this);
|
||||
|
||||
this.name = "RequirementError";
|
||||
|
||||
let msg = requirement.msg;
|
||||
if (!msg) {
|
||||
msg = 'The option "' + key + '" ';
|
||||
|
@ -154,5 +160,7 @@ function requirementError(key, requirement) {
|
|||
"must be one of the following types: " + requirement.is.join(", ") :
|
||||
"is invalid.";
|
||||
}
|
||||
return new Error(msg);
|
||||
|
||||
this.message = msg;
|
||||
}
|
||||
RequirementError.prototype = Object.create(Error.prototype);
|
||||
|
|
|
@ -31,6 +31,21 @@ function isNull(value) {
|
|||
}
|
||||
exports.isNull = isNull;
|
||||
|
||||
/**
|
||||
* Returns `true` if value is `null` or `undefined`.
|
||||
* It's equivalent to `== null`, but resolve the ambiguity of the writer
|
||||
* intention, makes clear that he's clearly checking both `null` and `undefined`
|
||||
* values, and it's not a typo for `=== null`.
|
||||
*/
|
||||
function isNil(value) {
|
||||
return value === null || value === undefined;
|
||||
}
|
||||
exports.isNil = isNil;
|
||||
|
||||
function isBoolean(value) {
|
||||
return typeof value === "boolean";
|
||||
}
|
||||
exports.isBoolean = isBoolean;
|
||||
/**
|
||||
* Returns `true` if value is a string.
|
||||
* @examples
|
||||
|
|
|
@ -29,7 +29,8 @@ const domPanel = require("./panel/utils");
|
|||
const { events } = require("./panel/events");
|
||||
const systemEvents = require("./system/events");
|
||||
const { filter, pipe } = require("./event/utils");
|
||||
const { getNodeView } = require("./view/core");
|
||||
const { getNodeView, getActiveView } = require("./view/core");
|
||||
const { isNil, isObject } = require("./lang/type");
|
||||
|
||||
if (isPrivateBrowsingSupported && isWindowPBSupported)
|
||||
throw Error('The panel module cannot be used with per-window private browsing at the moment, see Bug 816257');
|
||||
|
@ -65,11 +66,26 @@ function getAttachEventType(model) {
|
|||
let number = { is: ['number', 'undefined', 'null'] };
|
||||
let boolean = { is: ['boolean', 'undefined', 'null'] };
|
||||
|
||||
let panelContract = contract(merge({
|
||||
let rectContract = contract({
|
||||
top: number,
|
||||
right: number,
|
||||
bottom: number,
|
||||
left: number
|
||||
});
|
||||
|
||||
let rect = {
|
||||
is: ['object', 'undefined', 'null'],
|
||||
map: function(v) isNil(v) || !isObject(v) ? v : rectContract(v)
|
||||
}
|
||||
|
||||
let displayContract = contract({
|
||||
width: number,
|
||||
height: number,
|
||||
focus: boolean,
|
||||
}, loaderContract.rules));
|
||||
position: rect
|
||||
});
|
||||
|
||||
let panelContract = contract(merge({}, displayContract.rules, loaderContract.rules));
|
||||
|
||||
|
||||
function isDisposed(panel) !views.has(panel);
|
||||
|
@ -80,12 +96,12 @@ let views = new WeakMap();
|
|||
let workers = new WeakMap();
|
||||
|
||||
function viewFor(panel) views.get(panel)
|
||||
exports.viewFor = viewFor;
|
||||
|
||||
function modelFor(panel) models.get(panel)
|
||||
function panelFor(view) panels.get(view)
|
||||
function workerFor(panel) workers.get(panel)
|
||||
|
||||
getActiveView.define(Panel, viewFor);
|
||||
|
||||
// Utility function takes `panel` instance and makes sure it will be
|
||||
// automatically hidden as soon as other panel is shown.
|
||||
let setupAutoHide = new function() {
|
||||
|
@ -124,9 +140,10 @@ const Panel = Class({
|
|||
extends: WorkerHost(workerFor),
|
||||
setup: function setup(options) {
|
||||
let model = merge({
|
||||
width: 320,
|
||||
height: 240,
|
||||
defaultWidth: 320,
|
||||
defaultHeight: 240,
|
||||
focus: true,
|
||||
position: Object.freeze({}),
|
||||
}, panelContract(options));
|
||||
models.set(this, model);
|
||||
|
||||
|
@ -172,6 +189,9 @@ const Panel = Class({
|
|||
/* Public API: Panel.focus */
|
||||
get focus() modelFor(this).focus,
|
||||
|
||||
/* Public API: Panel.position */
|
||||
get position() modelFor(this).position,
|
||||
|
||||
get contentURL() modelFor(this).contentURL,
|
||||
set contentURL(value) {
|
||||
let model = modelFor(this);
|
||||
|
@ -183,13 +203,22 @@ const Panel = Class({
|
|||
get isShowing() !isDisposed(this) && domPanel.isOpen(viewFor(this)),
|
||||
|
||||
/* Public API: Panel.show */
|
||||
show: function show(anchor) {
|
||||
show: function show(options, anchor) {
|
||||
let model = modelFor(this);
|
||||
let view = viewFor(this);
|
||||
let anchorView = getNodeView(anchor);
|
||||
|
||||
options = merge({
|
||||
position: model.position,
|
||||
width: model.width,
|
||||
height: model.height,
|
||||
defaultWidth: model.defaultWidth,
|
||||
defaultHeight: model.defaultHeight,
|
||||
focus: model.focus
|
||||
}, displayContract(options));
|
||||
|
||||
if (!isDisposed(this))
|
||||
domPanel.show(view, model.width, model.height, model.focus, anchorView);
|
||||
domPanel.show(view, options, anchorView);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
@ -207,8 +236,8 @@ const Panel = Class({
|
|||
let model = modelFor(this);
|
||||
let view = viewFor(this);
|
||||
let change = panelContract({
|
||||
width: width || model.width,
|
||||
height: height || model.height
|
||||
width: width || model.width || model.defaultWidth,
|
||||
height: height || model.height || model.defaultHeight
|
||||
});
|
||||
|
||||
model.width = change.width
|
||||
|
|
|
@ -12,18 +12,67 @@ const { Cc, Ci } = require("chrome");
|
|||
const { setTimeout } = require("../timers");
|
||||
const { platform } = require("../system");
|
||||
const { getMostRecentBrowserWindow, getOwnerBrowserWindow,
|
||||
getHiddenWindow } = require("../window/utils");
|
||||
getHiddenWindow, getScreenPixelsPerCSSPixel } = require("../window/utils");
|
||||
|
||||
const { create: createFrame, swapFrameLoaders } = require("../frame/utils");
|
||||
const { window: addonWindow } = require("../addon/window");
|
||||
const { isNil } = require("../lang/type");
|
||||
const events = require("../system/events");
|
||||
|
||||
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
function open(panel, width, height, anchor) {
|
||||
function calculateRegion({ position, width, height, defaultWidth, defaultHeight }, rect) {
|
||||
let x, y;
|
||||
|
||||
let hasTop = !isNil(position.top);
|
||||
let hasRight = !isNil(position.right);
|
||||
let hasBottom = !isNil(position.bottom);
|
||||
let hasLeft = !isNil(position.left);
|
||||
let hasWidth = !isNil(width);
|
||||
let hasHeight = !isNil(height);
|
||||
|
||||
// if width is not specified by constructor or show's options, then get
|
||||
// the default width
|
||||
if (!hasWidth)
|
||||
width = defaultWidth;
|
||||
|
||||
// if height is not specified by constructor or show's options, then get
|
||||
// the default height
|
||||
if (!hasHeight)
|
||||
height = defaultHeight;
|
||||
|
||||
// default position is centered
|
||||
x = (rect.right - width) / 2;
|
||||
y = (rect.top + rect.bottom - height) / 2;
|
||||
|
||||
if (hasTop) {
|
||||
y = rect.top + position.top;
|
||||
|
||||
if (hasBottom && !hasHeight)
|
||||
height = rect.bottom - position.bottom - y;
|
||||
}
|
||||
else if (hasBottom) {
|
||||
y = rect.bottom - position.bottom - height;
|
||||
}
|
||||
|
||||
if (hasLeft) {
|
||||
x = position.left;
|
||||
|
||||
if (hasRight && !hasWidth)
|
||||
width = rect.right - position.right - x;
|
||||
}
|
||||
else if (hasRight) {
|
||||
x = rect.right - width - position.right;
|
||||
}
|
||||
|
||||
return {x: x, y: y, width: width, height: height};
|
||||
}
|
||||
|
||||
function open(panel, options, anchor) {
|
||||
// Wait for the XBL binding to be constructed
|
||||
if (!panel.openPopup) setTimeout(open, 50, panel, width, height, anchor);
|
||||
else display(panel, width, height, anchor);
|
||||
if (!panel.openPopup) setTimeout(open, 50, panel, options, anchor);
|
||||
else display(panel, options, anchor);
|
||||
}
|
||||
exports.open = open;
|
||||
|
||||
|
@ -52,29 +101,37 @@ function resize(panel, width, height) {
|
|||
}
|
||||
exports.resize = resize
|
||||
|
||||
function display(panel, width, height, anchor) {
|
||||
function display(panel, options, anchor) {
|
||||
let document = panel.ownerDocument;
|
||||
let x = null;
|
||||
let y = null;
|
||||
let position = null;
|
||||
|
||||
let x, y;
|
||||
let { width, height, defaultWidth, defaultHeight } = options;
|
||||
|
||||
let popupPosition = null;
|
||||
|
||||
// Panel XBL has some SDK incompatible styling decisions. We shim panel
|
||||
// instances until proper fix for Bug 859504 is shipped.
|
||||
shimDefaultStyle(panel);
|
||||
|
||||
if (!anchor) {
|
||||
// Open the popup in the middle of the window.
|
||||
x = document.documentElement.clientWidth / 2 - width / 2;
|
||||
y = document.documentElement.clientHeight / 2 - height / 2;
|
||||
position = null;
|
||||
// The XUL Panel doesn't have an arrow, so the margin needs to be reset
|
||||
// in order to, be positioned properly
|
||||
panel.style.margin = "0";
|
||||
|
||||
let viewportRect = document.defaultView.gBrowser.getBoundingClientRect();
|
||||
|
||||
({x, y, width, height}) = calculateRegion(options, viewportRect);
|
||||
}
|
||||
else {
|
||||
width = width || defaultWidth;
|
||||
height = height || defaultHeight;
|
||||
|
||||
// Open the popup by the anchor.
|
||||
let rect = anchor.getBoundingClientRect();
|
||||
|
||||
let window = anchor.ownerDocument.defaultView;
|
||||
|
||||
let zoom = window.mozScreenPixelsPerCSSPixel;
|
||||
let zoom = getScreenPixelsPerCSSPixel(window);
|
||||
let screenX = rect.left + window.mozInnerScreenX * zoom;
|
||||
let screenY = rect.top + window.mozInnerScreenY * zoom;
|
||||
|
||||
|
@ -92,7 +149,7 @@ function display(panel, width, height, anchor) {
|
|||
horizontal = "right";
|
||||
|
||||
let verticalInverse = vertical == "top" ? "bottom" : "top";
|
||||
position = vertical + "center " + verticalInverse + horizontal;
|
||||
popupPosition = vertical + "center " + verticalInverse + horizontal;
|
||||
|
||||
// Allow panel to flip itself if the panel can't be displayed at the
|
||||
// specified position (useful if we compute a bad position or if the
|
||||
|
@ -105,7 +162,7 @@ function display(panel, width, height, anchor) {
|
|||
panel.firstChild.style.width = width + "px";
|
||||
panel.firstChild.style.height = height + "px";
|
||||
|
||||
panel.openPopup(anchor, position, x, y);
|
||||
panel.openPopup(anchor, popupPosition, x, y);
|
||||
}
|
||||
exports.display = display;
|
||||
|
||||
|
@ -124,16 +181,16 @@ function shimDefaultStyle(panel) {
|
|||
});
|
||||
}
|
||||
|
||||
function show(panel, width, height, focus, anchor) {
|
||||
function show(panel, options, anchor) {
|
||||
// Prevent the panel from getting focus when showing up
|
||||
// if focus is set to false
|
||||
panel.setAttribute("noautofocus", !focus);
|
||||
|
||||
panel.setAttribute("noautofocus", !options.focus);
|
||||
|
||||
let window = anchor && getOwnerBrowserWindow(anchor);
|
||||
let { document } = window ? window : getMostRecentBrowserWindow();
|
||||
attach(panel, document);
|
||||
open(panel, width, height, anchor);
|
||||
|
||||
open(panel, options, anchor);
|
||||
}
|
||||
exports.show = show
|
||||
|
||||
|
|
|
@ -24,3 +24,6 @@ getNodeView.define(function(value) {
|
|||
});
|
||||
|
||||
exports.getNodeView = getNodeView;
|
||||
|
||||
let getActiveView = method("getActiveView");
|
||||
exports.getActiveView = getActiveView;
|
||||
|
|
|
@ -435,7 +435,7 @@ const WidgetViewTrait = LightTrait.compose(EventEmitterTrait, LightTrait({
|
|||
// This kind of ugly workaround, instead we should implement
|
||||
// `getNodeView` for the `Widget` class itself, but that's kind of
|
||||
// hard without cleaning things up.
|
||||
this.panel.show(getNodeView.implement({}, function() domNode));
|
||||
this.panel.show(null, getNodeView.implement({}, function() domNode));
|
||||
},
|
||||
|
||||
_isInWindow: function WidgetView__isInWindow(window) {
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
'use strict';
|
||||
|
||||
const { defer } = require('../core/promise');
|
||||
const { open: openWindow, onFocus } = require('./utils');
|
||||
const events = require('../system/events');
|
||||
const { open: openWindow, onFocus, getToplevelWindow } = require('./utils');
|
||||
|
||||
function open(uri, options) {
|
||||
return promise(openWindow.apply(null, arguments), 'load');
|
||||
|
@ -12,11 +13,19 @@ function open(uri, options) {
|
|||
exports.open = open;
|
||||
|
||||
function close(window) {
|
||||
// unload event could happen so fast that it is not resolved
|
||||
// if we listen to unload after calling close()
|
||||
let p = promise(window, 'unload');
|
||||
// We shouldn't wait for unload, as it is dispatched
|
||||
// before the window is actually closed.
|
||||
// `domwindowclosed` is a better match.
|
||||
let deferred = defer();
|
||||
let toplevelWindow = getToplevelWindow(window);
|
||||
events.on("domwindowclosed", function onclose({subject}) {
|
||||
if (subject == toplevelWindow) {
|
||||
events.off("domwindowclosed", onclose);
|
||||
deferred.resolve(window);
|
||||
}
|
||||
}, true);
|
||||
window.close();
|
||||
return p;
|
||||
return deferred.promise;
|
||||
}
|
||||
exports.close = close;
|
||||
|
||||
|
|
|
@ -113,6 +113,19 @@ function getBaseWindow(window) {
|
|||
}
|
||||
exports.getBaseWindow = getBaseWindow;
|
||||
|
||||
/**
|
||||
* Returns the `nsIDOMWindow` toplevel window for any child/inner window
|
||||
*/
|
||||
function getToplevelWindow(window) {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||
.rootTreeItem
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
}
|
||||
exports.getToplevelWindow = getToplevelWindow;
|
||||
|
||||
function getWindowDocShell(window) window.gBrowser.docShell;
|
||||
exports.getWindowDocShell = getWindowDocShell;
|
||||
|
||||
|
@ -341,6 +354,12 @@ function getFrames(window) {
|
|||
}
|
||||
exports.getFrames = getFrames;
|
||||
|
||||
function getScreenPixelsPerCSSPixel(window) {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils).screenPixelsPerCSSPixel;
|
||||
}
|
||||
exports.getScreenPixelsPerCSSPixel = getScreenPixelsPerCSSPixel;
|
||||
|
||||
function getOwnerBrowserWindow(node) {
|
||||
/**
|
||||
Takes DOM node and returns browser window that contains it.
|
||||
|
|
|
@ -70,7 +70,7 @@ exports.testShowPanelAndWidgetOnPrivateWindow = function(assert, done) {
|
|||
}
|
||||
});
|
||||
}
|
||||
}).show(window.gBrowser);
|
||||
}).show(null, window.gBrowser);
|
||||
},
|
||||
onUntrack: function(window) {
|
||||
if (window === myPrivateWindow) {
|
||||
|
|
|
@ -14,6 +14,7 @@ const { openDialog, getMostRecentBrowserWindow } = require('sdk/window/utils');
|
|||
const { openTab, getTabContentWindow, getActiveTab, setTabURL, closeTab } = require('sdk/tabs/utils');
|
||||
const promise = require("sdk/core/promise");
|
||||
const windowHelpers = require('sdk/window/helpers');
|
||||
const events = require("sdk/system/events");
|
||||
|
||||
function LoaderWithHookedConsole(module) {
|
||||
let globals = {};
|
||||
|
@ -71,13 +72,19 @@ exports.openWebpage = function openWebpage(url, enablePrivate) {
|
|||
private: enablePrivate
|
||||
});
|
||||
let deferred = promise.defer();
|
||||
win.addEventListener("load", function onLoad() {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
|
||||
let rawTab = getActiveTab(win);
|
||||
setTabURL(rawTab, url);
|
||||
deferred.resolve(getTabContentWindow(rawTab));
|
||||
});
|
||||
// Wait for delayed startup code to be executed, in order to ensure
|
||||
// that the window is really ready
|
||||
events.on("browser-delayed-startup-finished", function onReady({subject}) {
|
||||
if (subject == win) {
|
||||
events.off("browser-delayed-startup-finished", onReady, true);
|
||||
|
||||
let rawTab = getActiveTab(win);
|
||||
setTabURL(rawTab, url);
|
||||
deferred.resolve(getTabContentWindow(rawTab));
|
||||
}
|
||||
}, true);
|
||||
|
||||
return {
|
||||
ready: deferred.promise,
|
||||
close: function () {
|
||||
|
|
|
@ -937,49 +937,37 @@ exports['test ready event on new window tab'] = function(test) {
|
|||
};
|
||||
|
||||
exports['test unique tab ids'] = function(test) {
|
||||
test.waitUntilDone();
|
||||
var windows = require('sdk/windows').browserWindows;
|
||||
var { all, defer } = require('sdk/core/promise');
|
||||
|
||||
var windows = require('sdk/windows').browserWindows,
|
||||
tabIds = {}, win1, win2;
|
||||
function openWindow() {
|
||||
// console.log('in openWindow');
|
||||
let deferred = defer();
|
||||
let win = windows.open({
|
||||
url: "data:text/html;charset=utf-8,<html>foo</html>",
|
||||
});
|
||||
|
||||
let steps = [
|
||||
function (index) {
|
||||
win1 = windows.open({
|
||||
url: "data:text/html;charset=utf-8,foo",
|
||||
onOpen: function(window) {
|
||||
tabIds['tab1'] = window.tabs.activeTab.id;
|
||||
next(index);
|
||||
}
|
||||
win.on('open', function(window) {
|
||||
test.assert(window.tabs.length);
|
||||
test.assert(window.tabs.activeTab);
|
||||
test.assert(window.tabs.activeTab.id);
|
||||
deferred.resolve({
|
||||
id: window.tabs.activeTab.id,
|
||||
win: win
|
||||
});
|
||||
},
|
||||
function (index) {
|
||||
win2 = windows.open({
|
||||
url: "data:text/html;charset=utf-8,foo",
|
||||
onOpen: function(window) {
|
||||
tabIds['tab2'] = window.tabs.activeTab.id;
|
||||
next(index);
|
||||
}
|
||||
});
|
||||
},
|
||||
function (index) {
|
||||
test.assertNotEqual(tabIds.tab1, tabIds.tab2, "Tab ids should be unique.");
|
||||
win1.close();
|
||||
win2.close();
|
||||
test.done();
|
||||
}
|
||||
];
|
||||
|
||||
function next(index) {
|
||||
if (index === steps.length) {
|
||||
return;
|
||||
}
|
||||
let fn = steps[index];
|
||||
index++
|
||||
fn(index);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
// run!
|
||||
next(0);
|
||||
test.waitUntilDone();
|
||||
var one = openWindow(), two = openWindow();
|
||||
all([one, two]).then(function(results) {
|
||||
test.assertNotEqual(results[0].id, results[1].id, "tab Ids should not be equal.");
|
||||
results[0].win.close();
|
||||
results[1].win.close();
|
||||
test.done();
|
||||
});
|
||||
}
|
||||
|
||||
// related to Bug 671305
|
||||
|
|
|
@ -318,7 +318,7 @@ exports["test Anchor And Arrow"] = function(assert, done) {
|
|||
return;
|
||||
}
|
||||
let { panel, anchor } = queue.shift();
|
||||
panel.show(anchor);
|
||||
panel.show(null, anchor);
|
||||
}
|
||||
|
||||
let tabs= require("sdk/tabs");
|
||||
|
@ -462,6 +462,7 @@ exports["test Change Content URL"] = function(assert, done) {
|
|||
contentURL: "about:blank",
|
||||
contentScript: "self.port.emit('ready', document.location.href);"
|
||||
});
|
||||
|
||||
let count = 0;
|
||||
panel.port.on("ready", function (location) {
|
||||
count++;
|
||||
|
@ -651,7 +652,7 @@ if (isWindowPBSupported) {
|
|||
showTries++;
|
||||
panel.show();
|
||||
showTries++;
|
||||
panel.show(browserWindow.gBrowser);
|
||||
panel.show(null, browserWindow.gBrowser);
|
||||
|
||||
return promise;
|
||||
}).
|
||||
|
@ -703,9 +704,9 @@ if (isWindowPBSupported) {
|
|||
}
|
||||
});
|
||||
showTries++;
|
||||
panel.show(window.gBrowser);
|
||||
panel.show(null, window.gBrowser);
|
||||
showTries++;
|
||||
panel.show(browserWindow.gBrowser);
|
||||
panel.show(null, browserWindow.gBrowser);
|
||||
|
||||
return promise;
|
||||
}).
|
||||
|
@ -753,7 +754,7 @@ exports['test Style Applied Only Once'] = function (assert, done) {
|
|||
'self.port.on("check",function() { self.port.emit("count", document.getElementsByTagName("style").length); });' +
|
||||
'self.port.on("ping", function (count) { self.port.emit("pong", count); });'
|
||||
});
|
||||
|
||||
|
||||
panel.port.on('count', function (styleCount) {
|
||||
assert.equal(styleCount, 1, 'should only have one style');
|
||||
done();
|
||||
|
@ -836,7 +837,7 @@ else if (isGlobalPBSupported) {
|
|||
assert.ok(isPrivate(window), 'window is private');
|
||||
assert.equal(getWindow(window.gBrowser), window, 'private window elements returns window');
|
||||
assert.equal(getWindow(activeWindow.gBrowser), activeWindow, 'active window elements returns window');
|
||||
|
||||
|
||||
pb.once('stop', done);
|
||||
pb.deactivate();
|
||||
})
|
||||
|
|
|
@ -61,7 +61,7 @@ exports.testShowPanelAndWidgetOnPrivateWindow = function(assert, done) {
|
|||
}
|
||||
});
|
||||
}
|
||||
}).show(window.gBrowser);
|
||||
}).show(null, window.gBrowser);
|
||||
},
|
||||
onUntrack: function(window) {
|
||||
if (window === myPrivateWindow) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
const { Ci } = require('chrome');
|
||||
const { open, backgroundify, windows, isBrowser,
|
||||
getXULWindow, getBaseWindow, getMostRecentWindow,
|
||||
getXULWindow, getBaseWindow, getToplevelWindow, getMostRecentWindow,
|
||||
getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { close } = require('sdk/window/helpers');
|
||||
const windowUtils = require('sdk/deprecated/window-utils');
|
||||
|
@ -28,6 +28,16 @@ exports['test get nsIXULWindow from nsIDomWindow'] = function(assert) {
|
|||
'base returns nsIXULWindow');
|
||||
};
|
||||
|
||||
exports['test getToplevelWindow'] = function(assert) {
|
||||
let active = windowUtils.activeBrowserWindow;
|
||||
assert.equal(getToplevelWindow(active), active,
|
||||
'getToplevelWindow of toplevel window returns the same window');
|
||||
assert.equal(getToplevelWindow(active.content), active,
|
||||
'getToplevelWindow of tab window returns the browser window');
|
||||
assert.ok(getToplevelWindow(active) instanceof Ci.nsIDOMWindow,
|
||||
'getToplevelWindow returns nsIDOMWindow');
|
||||
};
|
||||
|
||||
exports['test top window creation'] = function(assert, done) {
|
||||
let window = open('data:text/html;charset=utf-8,Hello top window');
|
||||
assert.ok(~windows().indexOf(window), 'window was opened');
|
||||
|
@ -61,7 +71,10 @@ exports.testBackgroundify = function(assert, done) {
|
|||
'backgroundifyied window is in the list of windows');
|
||||
|
||||
// Wait for the window unload before ending test
|
||||
close(window).then(done);
|
||||
// backgroundified windows doesn't dispatch domwindowclosed event
|
||||
// so that we have to manually wait for unload event
|
||||
window.onunload = done;
|
||||
window.close();
|
||||
};
|
||||
|
||||
exports.testIsBrowser = function(assert) {
|
||||
|
|
|
@ -39,7 +39,7 @@ exports.testWindowTabsObject_alt = function(test) {
|
|||
test.assertNotEqual(window.tabs.activeTab, tab, "Correct active tab");
|
||||
|
||||
// end test
|
||||
tab.close(test.done());
|
||||
tab.close(test.done.bind(test));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -356,8 +356,6 @@ exports.testWindowOpenPrivateDefault = function(test) {
|
|||
url: 'about:mozilla',
|
||||
isPrivate: true,
|
||||
onOpen: function(window) {
|
||||
test.assertEqual();
|
||||
|
||||
let tab = window.tabs[0];
|
||||
tab.once('ready', function() {
|
||||
test.assertEqual(tab.url, 'about:mozilla', 'opened correct tab');
|
||||
|
|
|
@ -253,9 +253,7 @@ let DebuggerController = {
|
|||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}, {
|
||||
useSourceMaps: Services.prefs.getBoolPref("devtools.debugger.source-maps-enabled")
|
||||
});
|
||||
}, { useSourceMaps: Prefs.sourceMapsEnabled });
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -299,6 +297,29 @@ let DebuggerController = {
|
|||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}, { useSourceMaps: Prefs.sourceMapsEnabled });
|
||||
},
|
||||
|
||||
/**
|
||||
* Detach and reattach to the thread actor with useSourceMaps true, blow
|
||||
* away old scripts and get sources again.
|
||||
*/
|
||||
reconfigureThread: function DC_reconfigureThread(aUseSourceMaps) {
|
||||
this.client.reconfigureThread(aUseSourceMaps, (aResponse) => {
|
||||
if (aResponse.error) {
|
||||
let msg = "Couldn't reconfigure thread: " + aResponse.message;
|
||||
Cu.reportError(msg);
|
||||
dumpn(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the source list widget.
|
||||
DebuggerView.Sources.empty();
|
||||
SourceUtils.clearCache();
|
||||
this.SourceScripts._handleTabNavigation();
|
||||
// Update the stack frame list.
|
||||
this.activeThread._clearFrames();
|
||||
this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1659,6 +1680,7 @@ let Prefs = new ViewHelpers.Prefs("devtools.debugger", {
|
|||
variablesSortingEnabled: ["Bool", "ui.variables-sorting-enabled"],
|
||||
variablesOnlyEnumVisible: ["Bool", "ui.variables-only-enum-visible"],
|
||||
variablesSearchboxVisible: ["Bool", "ui.variables-searchbox-visible"],
|
||||
sourceMapsEnabled: ["Bool", "source-maps-enabled"],
|
||||
remoteHost: ["Char", "remote-host"],
|
||||
remotePort: ["Int", "remote-port"],
|
||||
remoteAutoConnect: ["Bool", "remote-autoconnect"],
|
||||
|
|
|
@ -187,6 +187,7 @@ function OptionsView() {
|
|||
this._toggleShowPanesOnStartup = this._toggleShowPanesOnStartup.bind(this);
|
||||
this._toggleShowVariablesOnlyEnum = this._toggleShowVariablesOnlyEnum.bind(this);
|
||||
this._toggleShowVariablesFilterBox = this._toggleShowVariablesFilterBox.bind(this);
|
||||
this._toggleShowOriginalSource = this._toggleShowOriginalSource.bind(this);
|
||||
}
|
||||
|
||||
OptionsView.prototype = {
|
||||
|
@ -201,11 +202,13 @@ OptionsView.prototype = {
|
|||
this._showPanesOnStartupItem = document.getElementById("show-panes-on-startup");
|
||||
this._showVariablesOnlyEnumItem = document.getElementById("show-vars-only-enum");
|
||||
this._showVariablesFilterBoxItem = document.getElementById("show-vars-filter-box");
|
||||
this._showOriginalSourceItem = document.getElementById("show-original-source");
|
||||
|
||||
this._pauseOnExceptionsItem.setAttribute("checked", Prefs.pauseOnExceptions);
|
||||
this._showPanesOnStartupItem.setAttribute("checked", Prefs.panesVisibleOnStartup);
|
||||
this._showVariablesOnlyEnumItem.setAttribute("checked", Prefs.variablesOnlyEnumVisible);
|
||||
this._showVariablesFilterBoxItem.setAttribute("checked", Prefs.variablesSearchboxVisible);
|
||||
this._showOriginalSourceItem.setAttribute("checked", Prefs.sourceMapsEnabled);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -262,10 +265,21 @@ OptionsView.prototype = {
|
|||
this._showVariablesFilterBoxItem.getAttribute("checked") == "true";
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the 'show original source' menuitem command.
|
||||
*/
|
||||
_toggleShowOriginalSource: function DVO__toggleShowOriginalSource() {
|
||||
let pref = Prefs.sourceMapsEnabled =
|
||||
this._showOriginalSourceItem.getAttribute("checked") == "true";
|
||||
|
||||
DebuggerController.reconfigureThread(pref);
|
||||
},
|
||||
|
||||
_button: null,
|
||||
_pauseOnExceptionsItem: null,
|
||||
_showPanesOnStartupItem: null,
|
||||
_showVariablesOnlyEnumItem: null,
|
||||
_showOriginalSourceItem: null,
|
||||
_showVariablesFilterBoxItem: null
|
||||
};
|
||||
|
||||
|
|
|
@ -64,6 +64,8 @@
|
|||
oncommand="DebuggerView.Options._toggleShowVariablesOnlyEnum()"/>
|
||||
<command id="toggleShowVariablesFilterBox"
|
||||
oncommand="DebuggerView.Options._toggleShowVariablesFilterBox()"/>
|
||||
<command id="toggleShowOriginalSource"
|
||||
oncommand="DebuggerView.Options._toggleShowOriginalSource()"/>
|
||||
</commandset>
|
||||
|
||||
<popupset id="debuggerPopupset">
|
||||
|
@ -160,6 +162,11 @@
|
|||
label="&debuggerUI.showVarsFilter;"
|
||||
accesskey="&debuggerUI.showVarsFilter.key;"
|
||||
command="toggleShowVariablesFilterBox"/>
|
||||
<menuitem id="show-original-source"
|
||||
type="checkbox"
|
||||
label="&debuggerUI.showOriginalSource;"
|
||||
accesskey="&debuggerUI.showOriginalSource.key;"
|
||||
command="toggleShowOriginalSource"/>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ MOCHITEST_BROWSER_TESTS = \
|
|||
browser_dbg_progress-listener-bug.js \
|
||||
browser_dbg_chrome-debugging.js \
|
||||
browser_dbg_source_maps-01.js \
|
||||
browser_dbg_source_maps-02.js \
|
||||
head.js \
|
||||
helpers.js \
|
||||
$(NULL)
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test that we can toggle between the original and generated sources.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "binary_search.html";
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
var gPrevPref = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
let resumed = false;
|
||||
let testStarted = false;
|
||||
|
||||
gPrevPref = Services.prefs.getBoolPref(
|
||||
"devtools.debugger.source-maps-enabled");
|
||||
Services.prefs.setBoolPref("devtools.debugger.source-maps-enabled", true);
|
||||
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
resumed = true;
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.panelWin;
|
||||
|
||||
gDebugger.addEventListener("Debugger:SourceShown", function _onSourceShown(aEvent) {
|
||||
gDebugger.removeEventListener("Debugger:SourceShown", _onSourceShown);
|
||||
// Show original sources should be already enabled.
|
||||
is(gPrevPref, false,
|
||||
"The source maps functionality should be disabled by default.");
|
||||
is(gDebugger.Prefs.sourceMapsEnabled, true,
|
||||
"The source maps pref should be true from startup.");
|
||||
is(gDebugger.DebuggerView.Options._showOriginalSourceItem.getAttribute("checked"),
|
||||
"true", "Source maps should be enabled from startup. ")
|
||||
|
||||
ok(aEvent.detail.url.indexOf(".coffee") != -1,
|
||||
"The debugger should show the source mapped coffee script file.");
|
||||
ok(aEvent.detail.url.indexOf(".js") == -1,
|
||||
"The debugger should not show the generated js script file.");
|
||||
ok(gDebugger.editor.getText().search(/isnt/) != -1,
|
||||
"The debugger's editor should have the coffee script source displayed.");
|
||||
ok(gDebugger.editor.getText().search(/function/) == -1,
|
||||
"The debugger's editor should not have the JS source displayed.");
|
||||
|
||||
testToggleGeneratedSource();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testToggleGeneratedSource() {
|
||||
gDebugger.addEventListener("Debugger:SourceShown", function _onSourceShown(aEvent) {
|
||||
gDebugger.removeEventListener("Debugger:SourceShown", _onSourceShown);
|
||||
|
||||
is(gDebugger.Prefs.sourceMapsEnabled, false,
|
||||
"The source maps pref should have been set to false.");
|
||||
is(gDebugger.DebuggerView.Options._showOriginalSourceItem.getAttribute("checked"),
|
||||
"false", "Source maps should be enabled from startup. ")
|
||||
|
||||
ok(aEvent.detail.url.indexOf(".coffee") == -1,
|
||||
"The debugger should not show the source mapped coffee script file.");
|
||||
ok(aEvent.detail.url.indexOf(".js") != -1,
|
||||
"The debugger should show the generated js script file.");
|
||||
ok(gDebugger.editor.getText().search(/isnt/) == -1,
|
||||
"The debugger's editor should have the coffee script source displayed.");
|
||||
ok(gDebugger.editor.getText().search(/function/) != -1,
|
||||
"The debugger's editor should not have the JS source displayed.");
|
||||
|
||||
testSetBreakpoint();
|
||||
});
|
||||
|
||||
// Disable source maps.
|
||||
gDebugger.DebuggerView.Options._showOriginalSourceItem.setAttribute("checked",
|
||||
"false");
|
||||
gDebugger.DebuggerView.Options._toggleShowOriginalSource();
|
||||
}
|
||||
|
||||
function testSetBreakpoint() {
|
||||
let { activeThread } = gDebugger.DebuggerController;
|
||||
activeThread.setBreakpoint({
|
||||
url: EXAMPLE_URL + "binary_search.js",
|
||||
line: 7
|
||||
}, function (aResponse, bpClient) {
|
||||
ok(!aResponse.error,
|
||||
"Should be able to set a breakpoint in a JavaScript file.");
|
||||
testHitBreakpoint();
|
||||
});
|
||||
}
|
||||
|
||||
function testHitBreakpoint() {
|
||||
let { activeThread } = gDebugger.DebuggerController;
|
||||
activeThread.resume(function (aResponse) {
|
||||
ok(!aResponse.error, "Shouldn't get an error resuming");
|
||||
is(aResponse.type, "resumed", "Type should be 'resumed'");
|
||||
|
||||
activeThread.addOneTimeListener("framesadded", function (aEvent, aPacket) {
|
||||
// Make sure that we have JavaScript stack frames.
|
||||
let frames = gDebugger.DebuggerView.StackFrames._container._list;
|
||||
let childNodes = frames.childNodes;
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
|
||||
"Correct number of frames.");
|
||||
ok(frames.querySelector("#stackframe-0 .dbg-stackframe-details")
|
||||
.getAttribute("value").search(/js/),
|
||||
"First frame should be a JS frame.");
|
||||
|
||||
waitForCaretPos(6, testToggleOnPause);
|
||||
});
|
||||
|
||||
// This will cause the breakpoint to be hit, and put us back in the paused
|
||||
// stated.
|
||||
executeSoon(function() {
|
||||
gDebuggee.binary_search([0, 2, 3, 5, 7, 10], 5);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testToggleOnPause() {
|
||||
gDebugger.addEventListener("Debugger:SourceShown", function _onSourceShown(aEvent) {
|
||||
gDebugger.removeEventListener("Debugger:SourceShown", _onSourceShown);
|
||||
|
||||
is(gDebugger.Prefs.sourceMapsEnabled, true,
|
||||
"The source maps pref should have been set to true.");
|
||||
is(gDebugger.DebuggerView.Options._showOriginalSourceItem.getAttribute("checked"),
|
||||
"true", "Source maps should be enabled. ")
|
||||
|
||||
ok(aEvent.detail.url.indexOf(".coffee") != -1,
|
||||
"The debugger should show the source mapped coffee script file.");
|
||||
ok(aEvent.detail.url.indexOf(".js") == -1,
|
||||
"The debugger should not show the generated js script file.");
|
||||
ok(gDebugger.editor.getText().search(/isnt/) != -1,
|
||||
"The debugger's editor should not have the coffee script source displayed.");
|
||||
ok(gDebugger.editor.getText().search(/function/) == -1,
|
||||
"The debugger's editor should have the JS source displayed.");
|
||||
|
||||
// Make sure that we have coffee script stack frames.
|
||||
let frames = gDebugger.DebuggerView.StackFrames._container._list;
|
||||
let childNodes = frames.childNodes;
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
|
||||
"Correct number of frames.");
|
||||
ok(frames.querySelector("#stackframe-0 .dbg-stackframe-details")
|
||||
.getAttribute("value").search(/coffee/),
|
||||
"First frame should be a coffee script frame.");
|
||||
|
||||
waitForCaretPos(4, resumeAndFinish);
|
||||
});
|
||||
|
||||
// Enable source maps.
|
||||
gDebugger.DebuggerView.Options._showOriginalSourceItem.setAttribute("checked",
|
||||
"true");
|
||||
gDebugger.DebuggerView.Options._toggleShowOriginalSource();
|
||||
}
|
||||
|
||||
function resumeAndFinish()
|
||||
{
|
||||
let { activeThread } = gDebugger.DebuggerController;
|
||||
activeThread.resume(function (aResponse) {
|
||||
ok(!aResponse.error, "Shouldn't get an error resuming");
|
||||
is(aResponse.type, "resumed", "Type should be 'resumed'");
|
||||
|
||||
closeDebuggerAndFinish();
|
||||
});
|
||||
}
|
||||
|
||||
function waitForCaretPos(number, callback)
|
||||
{
|
||||
// Poll every few milliseconds until the source editor line is active.
|
||||
let count = 0;
|
||||
let intervalID = window.setInterval(function() {
|
||||
info("count: " + count + " ");
|
||||
if (++count > 50) {
|
||||
ok(false, "Timed out while polling for the line.");
|
||||
window.clearInterval(intervalID);
|
||||
return closeDebuggerAndFinish();
|
||||
}
|
||||
if (gDebugger.DebuggerView.editor.getCaretPosition().line != number) {
|
||||
return;
|
||||
}
|
||||
is(gDebugger.DebuggerView.editor.getCaretPosition().line, number,
|
||||
"The right line is focused.")
|
||||
// We got the source editor at the expected line, it's safe to callback.
|
||||
window.clearInterval(intervalID);
|
||||
callback();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.setBoolPref("devtools.debugger.source-maps-enabled", false);
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
gPrevPref = null;
|
||||
});
|
|
@ -320,6 +320,7 @@ TabTarget.prototype = {
|
|||
let event = Object.create(null);
|
||||
event.url = aPacket.url;
|
||||
event.title = aPacket.title;
|
||||
event.nativeConsoleAPI = aPacket.nativeConsoleAPI;
|
||||
// Send any stored event payload (DOMWindow or nsIRequest) for backwards
|
||||
// compatibility with non-remotable tools.
|
||||
if (aPacket.state == "start") {
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
<hbox flex="1">
|
||||
<box flex="1" class="devtools-responsive-container">
|
||||
<vbox flex="1">
|
||||
<toolbar id="inspector-toolbar"
|
||||
class="devtools-toolbar"
|
||||
|
@ -91,5 +91,5 @@
|
|||
<tabs/>
|
||||
<tabpanels flex="1"/>
|
||||
</tabbox>
|
||||
</hbox>
|
||||
</box>
|
||||
</window>
|
||||
|
|
|
@ -505,7 +505,8 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
break;
|
||||
}
|
||||
case "contentSize": {
|
||||
let size = (aValue / 1024).toFixed(CONTENT_SIZE_DECIMALS);
|
||||
let kb = aValue / 1024;
|
||||
let size = L10N.numberWithDecimals(kb, CONTENT_SIZE_DECIMALS);
|
||||
let node = $(".requests-menu-size", aItem.target);
|
||||
let text = L10N.getFormatStr("networkMenu.sizeKB", size);
|
||||
node.setAttribute("value", text);
|
||||
|
@ -522,7 +523,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
}
|
||||
case "totalTime": {
|
||||
let node = $(".requests-menu-timings-total", aItem.target);
|
||||
let text = L10N.getFormatStr("networkMenu.totalMS", aValue);
|
||||
let text = L10N.getFormatStr("networkMenu.totalMS", aValue); // integer
|
||||
node.setAttribute("value", text);
|
||||
node.setAttribute("tooltiptext", text);
|
||||
break;
|
||||
|
@ -540,7 +541,8 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
|
|||
*/
|
||||
_createWaterfallView: function NVRM__createWaterfallView(aItem, aTimings) {
|
||||
let { target, attachment } = aItem;
|
||||
let sections = ["blocked", "dns", "connect", "send", "wait", "receive"];
|
||||
let sections = ["dns", "connect", "send", "wait", "receive"];
|
||||
// Skipping "blocked" because it doesn't work yet.
|
||||
|
||||
let timingsNode = $(".requests-menu-timings", target);
|
||||
let startCapNode = $(".requests-menu-timings-cap.start", timingsNode);
|
||||
|
@ -879,9 +881,10 @@ create({ constructor: NetworkDetailsView, proto: MenuContainer.prototype }, {
|
|||
* The message received from the server.
|
||||
*/
|
||||
_addHeaders: function NVND__addHeaders(aName, aResponse) {
|
||||
let kb = (aResponse.headersSize / 1024).toFixed(HEADERS_SIZE_DECIMALS);
|
||||
let size = L10N.getFormatStr("networkMenu.sizeKB", kb);
|
||||
let headersScope = this._headers.addScope(aName + " (" + size + ")");
|
||||
let kb = aResponse.headersSize / 1024;
|
||||
let size = L10N.numberWithDecimals(kb, HEADERS_SIZE_DECIMALS);
|
||||
let text = L10N.getFormatStr("networkMenu.sizeKB", size);
|
||||
let headersScope = this._headers.addScope(aName + " (" + text + ")");
|
||||
headersScope.expanded = true;
|
||||
|
||||
for (let header of aResponse.headers) {
|
||||
|
|
|
@ -6,3 +6,15 @@
|
|||
#response-content-image-box {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#timings-summary-blocked {
|
||||
display: none; /* This doesn't work yet. */
|
||||
}
|
||||
|
||||
/* Responsive sidebar */
|
||||
@media (max-width: 700px) {
|
||||
#details-pane-toggle,
|
||||
.requests-menu-waterfall {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<script type="text/javascript" src="netmonitor-controller.js"/>
|
||||
<script type="text/javascript" src="netmonitor-view.js"/>
|
||||
|
||||
<hbox id="body" flex="1">
|
||||
<box id="body" flex="1" class="devtools-responsive-container">
|
||||
<vbox id="network-table" flex="1">
|
||||
<toolbar id="requests-menu-toolbar"
|
||||
class="devtools-toolbar"
|
||||
|
@ -262,6 +262,6 @@
|
|||
</tabpanel>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
</hbox>
|
||||
</box>
|
||||
|
||||
</window>
|
||||
|
|
|
@ -48,7 +48,7 @@ function test() {
|
|||
statusText: "OK",
|
||||
type: "json",
|
||||
fullMimeType: "application/json; charset=utf-8",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.03),
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.02),
|
||||
time: true
|
||||
});
|
||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4),
|
||||
|
@ -66,7 +66,7 @@ function test() {
|
|||
statusText: "OK",
|
||||
type: "png",
|
||||
fullMimeType: "image/png",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.76),
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0.75),
|
||||
time: true
|
||||
});
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ function test() {
|
|||
|
||||
// This is receiving over 80 KB of json and will populate over 6000 items
|
||||
// in a variables view instance. Debug builds are slow.
|
||||
requestLongerTimeout(2);
|
||||
requestLongerTimeout(3);
|
||||
|
||||
let { document, L10N, SourceEditor, NetMonitorView } = aMonitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
@ -25,7 +25,7 @@ function test() {
|
|||
statusText: "OK",
|
||||
type: "json",
|
||||
fullMimeType: "text/json; charset=utf-8",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 83.96),
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 83.95),
|
||||
time: true
|
||||
});
|
||||
|
||||
|
|
|
@ -73,14 +73,15 @@ function test() {
|
|||
|
||||
is(responseScope.querySelector(".name").getAttribute("value"),
|
||||
L10N.getStr("responseHeaders") + " (" +
|
||||
L10N.getFormatStr("networkMenu.sizeKB", "0.169") + ")",
|
||||
L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(0.168, 3)) + ")",
|
||||
"The response headers scope doesn't have the correct title.");
|
||||
|
||||
ok(requestScope.querySelector(".name").getAttribute("value").contains(
|
||||
L10N.getStr("requestHeaders") + " (0."),
|
||||
// Can't test for full request headers title because the size may
|
||||
// vary across platforms ("User-Agent" header differs).
|
||||
L10N.getStr("requestHeaders") + " (0"),
|
||||
"The request headers scope doesn't have the correct title.");
|
||||
// Can't test for full request headers title because the size may
|
||||
// vary across platforms ("User-Agent" header differs). We're pretty
|
||||
// sure it's smaller than 1 MB though, so it starts with a 0.
|
||||
|
||||
is(responseScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
|
||||
"Connection", "The first response header name was incorrect.");
|
||||
|
|
|
@ -24,7 +24,7 @@ function test() {
|
|||
statusText: "Switching Protocols",
|
||||
type: "plain",
|
||||
fullMimeType: "text/plain; charset=utf-8",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", "0.00"),
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0),
|
||||
time: true
|
||||
});
|
||||
verifyRequestItemTarget(requestItems[1] = RequestsMenu.getItemAtIndex(1),
|
||||
|
@ -42,7 +42,7 @@ function test() {
|
|||
statusText: "See Other",
|
||||
type: "plain",
|
||||
fullMimeType: "text/plain; charset=utf-8",
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", "0.00"),
|
||||
size: L10N.getFormatStr("networkMenu.sizeKB", 0),
|
||||
time: true
|
||||
});
|
||||
verifyRequestItemTarget(requestItems[3] = RequestsMenu.getItemAtIndex(3),
|
||||
|
|
|
@ -404,8 +404,8 @@ VariablesView.prototype = {
|
|||
return;
|
||||
}
|
||||
this._searchboxContainer.parentNode.removeChild(this._searchboxContainer);
|
||||
this._searchboxNode.addEventListener("input", this._onSearchboxInput, false);
|
||||
this._searchboxNode.addEventListener("keypress", this._onSearchboxKeyPress, false);
|
||||
this._searchboxNode.removeEventListener("input", this._onSearchboxInput, false);
|
||||
this._searchboxNode.removeEventListener("keypress", this._onSearchboxKeyPress, false);
|
||||
|
||||
this._searchboxContainer = null;
|
||||
this._searchboxNode = null;
|
||||
|
@ -1543,7 +1543,9 @@ Scope.prototype = {
|
|||
* The click listener for this scope's title.
|
||||
*/
|
||||
_onClick: function S__onClick(e) {
|
||||
if (e.target == this._inputNode) {
|
||||
if (e.target == this._inputNode ||
|
||||
e.target == this._editNode ||
|
||||
e.target == this._deleteNode) {
|
||||
return;
|
||||
}
|
||||
this.toggle();
|
||||
|
|
|
@ -201,6 +201,32 @@ ViewHelpers.L10N.prototype = {
|
|||
*/
|
||||
getFormatStr: function L10N_getFormatStr(aName, ...aArgs) {
|
||||
return this.stringBundle.formatStringFromName(aName, aArgs, aArgs.length);
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts a number to a locale-aware string format and keeps a certain
|
||||
* number of decimals.
|
||||
*
|
||||
* @param number aNumber
|
||||
* The number to convert.
|
||||
* @param number aDecimals [optional]
|
||||
* Total decimals to keep.
|
||||
* @return string
|
||||
* The localized number as a string.
|
||||
*/
|
||||
numberWithDecimals: function L10N__numberWithDecimals(aNumber, aDecimals = 0) {
|
||||
// If this is an integer, don't do anything special.
|
||||
if (aNumber == (aNumber | 0)) {
|
||||
return aNumber;
|
||||
}
|
||||
// Remove {n} trailing decimals. Can't use toFixed(n) because
|
||||
// toLocaleString converts the number to a string. Also can't use
|
||||
// toLocaleString(, { maximumFractionDigits: n }) because it's not
|
||||
// implemented on OS X (bug 368838). Gross.
|
||||
let localized = aNumber.toLocaleString(); // localize
|
||||
let padded = localized + new Array(aDecimals).join("0"); // pad with zeros
|
||||
let match = padded.match("([^]*?\\d{" + aDecimals + "})\\d*$");
|
||||
return match.pop();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -36,6 +36,11 @@
|
|||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
.variables-view-scope > .title,
|
||||
.variable-or-property > .title {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.variables-view-scope[non-header] > .title,
|
||||
.variable-or-property[non-header] > .title,
|
||||
.variable-or-property[non-match] > .title {
|
||||
|
|
|
@ -80,6 +80,7 @@ this.TiltVisualizer = function TiltVisualizer(aProperties)
|
|||
* Save a reference to the top-level window.
|
||||
*/
|
||||
this.chromeWindow = aProperties.chromeWindow;
|
||||
this.tab = aProperties.tab;
|
||||
|
||||
/**
|
||||
* The canvas element used for rendering the visualization.
|
||||
|
@ -99,8 +100,6 @@ this.TiltVisualizer = function TiltVisualizer(aProperties)
|
|||
aProperties.onError || null,
|
||||
aProperties.onLoad || null);
|
||||
|
||||
this.bindToInspector(aProperties.tab);
|
||||
|
||||
/**
|
||||
* Visualization mouse and keyboard controller.
|
||||
*/
|
||||
|
@ -110,11 +109,12 @@ this.TiltVisualizer = function TiltVisualizer(aProperties)
|
|||
TiltVisualizer.prototype = {
|
||||
|
||||
/**
|
||||
* Initializes the visualizer
|
||||
* Initializes the visualizer.
|
||||
*/
|
||||
init: function TV_init()
|
||||
{
|
||||
this.presenter.init();
|
||||
this.bindToInspector(this.tab);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,6 +41,7 @@ MOCHITEST_BROWSER_FILES = \
|
|||
browser_tilt_math06.js \
|
||||
browser_tilt_math07.js \
|
||||
browser_tilt_picking.js \
|
||||
browser_tilt_picking_inspector.js \
|
||||
browser_tilt_picking_delete.js \
|
||||
browser_tilt_picking_highlight01-offs.js \
|
||||
browser_tilt_picking_highlight01.js \
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
let presenter;
|
||||
|
||||
function test() {
|
||||
if (!isTiltEnabled()) {
|
||||
info("Skipping highlight test because Tilt isn't enabled.");
|
||||
return;
|
||||
}
|
||||
if (!isWebGLSupported()) {
|
||||
info("Skipping highlight test because WebGL isn't supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
createTab(function() {
|
||||
let { TargetFactory } = Cu.import("resource:///modules/devtools/Target.jsm", {});
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||
let contentDocument = toolbox.target.tab.linkedBrowser.contentDocument;
|
||||
let div = contentDocument.getElementById("first-law");
|
||||
toolbox.getCurrentPanel().selection.setNode(div);
|
||||
|
||||
createTilt({
|
||||
onTiltOpen: function(instance)
|
||||
{
|
||||
presenter = instance.presenter;
|
||||
whenOpen();
|
||||
}
|
||||
}, false, function suddenDeath()
|
||||
{
|
||||
info("Tilt could not be initialized properly.");
|
||||
cleanup();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function whenOpen() {
|
||||
ok(presenter._currentSelection > 0,
|
||||
"Highlighting a node didn't work properly.");
|
||||
ok(!presenter._highlight.disabled,
|
||||
"After highlighting a node, it should be highlighted. D'oh.");
|
||||
ok(!presenter.controller.arcball._resetInProgress,
|
||||
"Highlighting a node that's already visible shouldn't trigger a reset.");
|
||||
|
||||
executeSoon(function() {
|
||||
Services.obs.addObserver(cleanup, DESTROYED, false);
|
||||
Tilt.destroy(Tilt.currentWindowId);
|
||||
});
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
Services.obs.removeObserver(cleanup, DESTROYED);
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
|
@ -4,45 +4,72 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const TEST_REPLACED_API_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-replaced-api.html";
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/testscript.js";
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// First test that the warning does not appear on a normal page (about:blank)
|
||||
addTab("about:blank");
|
||||
// First test that the warning does not appear on a page that doesn't override
|
||||
// the window.console object.
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
testOpenWebConsole(false);
|
||||
openConsole(null, testWarningNotPresent);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function testWarningPresent() {
|
||||
// Then test that the warning does appear on a page that replaces the API
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
testOpenWebConsole(true);
|
||||
}, true);
|
||||
browser.contentWindow.location = TEST_REPLACED_API_URI;
|
||||
}
|
||||
function testWarningNotPresent(hud)
|
||||
{
|
||||
is(hud.outputNode.textContent.indexOf("logging API"), -1,
|
||||
"no warning displayed");
|
||||
|
||||
function testOpenWebConsole(shouldWarn) {
|
||||
openConsole(null, function(hud) {
|
||||
waitForSuccess({
|
||||
name: (shouldWarn ? "no " : "") + "API replacement warning",
|
||||
validatorFn: function()
|
||||
{
|
||||
let pos = hud.outputNode.textContent.indexOf("disabled by");
|
||||
return shouldWarn ? pos > -1 : pos == -1;
|
||||
},
|
||||
successFn: function() {
|
||||
if (shouldWarn) {
|
||||
finishTest();
|
||||
}
|
||||
else {
|
||||
closeConsole(null, testWarningPresent);
|
||||
}
|
||||
},
|
||||
failureFn: finishTest,
|
||||
// Bug 862024: make sure the warning doesn't show after page reload.
|
||||
info("reload " + TEST_URI);
|
||||
executeSoon(() => content.location.reload());
|
||||
|
||||
waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
text: "testscript.js",
|
||||
category: CATEGORY_NETWORK,
|
||||
}],
|
||||
}).then(() => executeSoon(() => {
|
||||
is(hud.outputNode.textContent.indexOf("logging API"), -1,
|
||||
"no warning displayed");
|
||||
|
||||
closeConsole(null, loadTestPage);
|
||||
}));
|
||||
}
|
||||
|
||||
function loadTestPage()
|
||||
{
|
||||
info("load test " + TEST_REPLACED_API_URI);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
openConsole(null, testWarningPresent);
|
||||
}, true);
|
||||
content.location = TEST_REPLACED_API_URI;
|
||||
}
|
||||
|
||||
function testWarningPresent(hud)
|
||||
{
|
||||
info("wait for the warning to show");
|
||||
let warning = {
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
text: /logging API .+ disabled by a script/,
|
||||
category: CATEGORY_JS,
|
||||
severity: SEVERITY_WARNING,
|
||||
}],
|
||||
};
|
||||
|
||||
waitForMessages(warning).then(() => {
|
||||
hud.jsterm.clearOutput();
|
||||
|
||||
executeSoon(() => {
|
||||
info("reload the test page and wait for the warning to show");
|
||||
waitForMessages(warning).then(finishTest);
|
||||
content.location.reload();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4714,16 +4714,16 @@ WebConsoleConnectionProxy.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* The "tabNavigated" message type handler. We redirect any message to
|
||||
* the UI for displaying.
|
||||
* The "will-navigate" and "navigate" event handlers. We redirect any message
|
||||
* to the UI for displaying.
|
||||
*
|
||||
* @private
|
||||
* @param string aType
|
||||
* Message type.
|
||||
* @param string aEvent
|
||||
* Event type.
|
||||
* @param object aPacket
|
||||
* The message received from the server.
|
||||
*/
|
||||
_onTabNavigated: function WCCP__onTabNavigated(aType, aPacket)
|
||||
_onTabNavigated: function WCCP__onTabNavigated(aEvent, aPacket)
|
||||
{
|
||||
if (!this.owner) {
|
||||
return;
|
||||
|
@ -4733,7 +4733,7 @@ WebConsoleConnectionProxy.prototype = {
|
|||
this.owner.onLocationChange(aPacket.url, aPacket.title);
|
||||
}
|
||||
|
||||
if (aType == "navigate" && !aPacket.nativeConsoleAPI) {
|
||||
if (aEvent == "navigate" && !aPacket.nativeConsoleAPI) {
|
||||
this.owner.logWarningAboutReplacedAPI();
|
||||
}
|
||||
},
|
||||
|
@ -4775,7 +4775,8 @@ WebConsoleConnectionProxy.prototype = {
|
|||
this.client.removeListener("networkEvent", this._onNetworkEvent);
|
||||
this.client.removeListener("networkEventUpdate", this._onNetworkEventUpdate);
|
||||
this.client.removeListener("fileActivity", this._onFileActivity);
|
||||
this.client.removeListener("tabNavigated", this._onTabNavigated);
|
||||
this.target.off("will-navigate", this._onTabNavigated);
|
||||
this.target.off("navigate", this._onTabNavigated);
|
||||
|
||||
this.client = null;
|
||||
this.webConsoleClient = null;
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
<hbox class="hud-outer-wrapper" flex="1">
|
||||
<box class="hud-outer-wrapper devtools-responsive-container" flex="1">
|
||||
<vbox class="hud-console-wrapper" flex="1">
|
||||
<toolbar class="hud-console-filter-toolbar devtools-toolbar" mode="full">
|
||||
<toolbarbutton label="&btnPageNet.label;" type="menu-button"
|
||||
|
@ -145,5 +145,5 @@
|
|||
<tabs/>
|
||||
<tabpanels flex="1"/>
|
||||
</tabbox>
|
||||
</hbox>
|
||||
</box>
|
||||
</window>
|
||||
|
|
|
@ -65,6 +65,12 @@
|
|||
<!ENTITY debuggerUI.showOnlyEnum "Show only enumerable properties">
|
||||
<!ENTITY debuggerUI.showOnlyEnum.key "P">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.showOriginalSource): This is the label for
|
||||
- the checkbox that toggles the display of original or sourcemap-derived
|
||||
- sources. -->
|
||||
<!ENTITY debuggerUI.showOriginalSource "Show original sources">
|
||||
<!ENTITY debuggerUI.showOriginalSource.key "O">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.searchPanelTitle): This is the text that
|
||||
- appears in the filter panel popup as a description. -->
|
||||
<!ENTITY debuggerUI.searchPanelTitle "Operators">
|
||||
|
|
|
@ -185,6 +185,10 @@ let Util = {
|
|||
aElement instanceof Ci.nsIDOMHTMLTextAreaElement);
|
||||
},
|
||||
|
||||
isMultilineInput: function isMultilineInput(aElement) {
|
||||
return (aElement instanceof Ci.nsIDOMHTMLTextAreaElement);
|
||||
},
|
||||
|
||||
isLink: function isLink(aElement) {
|
||||
return ((aElement instanceof Ci.nsIDOMHTMLAnchorElement && aElement.href) ||
|
||||
(aElement instanceof Ci.nsIDOMHTMLAreaElement && aElement.href) ||
|
||||
|
|
|
@ -68,12 +68,12 @@
|
|||
|
||||
<binding id="autocomplete-popup">
|
||||
<content orient="horizontal">
|
||||
<xul:vbox id="results-vbox" class="meta-section viewable-height">
|
||||
<xul:vbox id="results-vbox" class="meta-section viewable-height" flex="1">
|
||||
<xul:label class="meta-section-title" value="&autocompleteResultsHeader.label;"/>
|
||||
<richgrid id="results-richgrid" anonid="results" seltype="single" flex="1"/>
|
||||
</xul:vbox>
|
||||
|
||||
<xul:vbox id="searches-vbox" class="meta-section viewable-height">
|
||||
<xul:vbox id="searches-vbox" class="meta-section viewable-height" flex="1">
|
||||
<xul:label class="meta-section-title" value="&autocompleteSearchesHeader.label;"/>
|
||||
<richgrid id="searches-richgrid" anonid="searches" seltype="single" flex="1"/>
|
||||
</xul:vbox>
|
||||
|
|
|
@ -569,11 +569,16 @@ var BrowserUI = {
|
|||
break;
|
||||
case "metro_viewstate_changed":
|
||||
this._adjustDOMforViewState();
|
||||
let autocomplete = document.getElementById("start-autocomplete");
|
||||
if (aData == "snapped") {
|
||||
FlyoutPanelsUI.hide();
|
||||
// Order matters (need grids to get dimensions, etc), now
|
||||
// let snapped grid know to refresh/redraw
|
||||
Services.obs.notifyObservers(null, "metro_viewstate_dom_snapped", null);
|
||||
autocomplete.setAttribute("orient", "vertical");
|
||||
}
|
||||
else {
|
||||
autocomplete.setAttribute("orient", "horizontal");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -294,7 +294,7 @@
|
|||
</scrollbox>
|
||||
</vbox>
|
||||
<!-- Autocompletion interface -->
|
||||
<box id="start-autocomplete"/>
|
||||
<box id="start-autocomplete" observes="bcast_windowState"/>
|
||||
</hbox>
|
||||
</vbox> <!-- end tray -->
|
||||
|
||||
|
|
|
@ -842,13 +842,16 @@ var SelectionHandler = {
|
|||
|
||||
let orientation = this._pointOrientationToRect(aClientPoint);
|
||||
let result = { speed: 1, trigger: false, start: false, end: false };
|
||||
let ml = Util.isMultilineInput(this._targetElement);
|
||||
|
||||
if (orientation.left || orientation.top) {
|
||||
// This could be improved such that we only select to the beginning of
|
||||
// the line when dragging left but not up.
|
||||
if (orientation.left || (ml && orientation.top)) {
|
||||
this._addEditSelection(kSelectionNodeAnchor);
|
||||
result.speed = orientation.left + orientation.top;
|
||||
result.trigger = true;
|
||||
result.end = true;
|
||||
} else if (orientation.right || orientation.bottom) {
|
||||
} else if (orientation.right || (ml && orientation.bottom)) {
|
||||
this._addEditSelection(kSelectionNodeFocus);
|
||||
result.speed = orientation.right + orientation.bottom;
|
||||
result.trigger = true;
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
// Y axis scroll distance that will disable this module and cancel selection
|
||||
const kDisableOnScrollDistance = 25;
|
||||
|
||||
// Drag hysteresis programmed into monocle drag moves
|
||||
const kDragHysteresisDistance = 10;
|
||||
|
||||
/*
|
||||
* Markers
|
||||
*/
|
||||
|
@ -99,6 +102,8 @@ Marker.prototype = {
|
|||
_selectionHelperUI: null,
|
||||
_xPos: 0,
|
||||
_yPos: 0,
|
||||
_xDrag: 0,
|
||||
_yDrag: 0,
|
||||
_tag: "",
|
||||
_hPlane: 0,
|
||||
_vPlane: 0,
|
||||
|
@ -174,6 +179,8 @@ Marker.prototype = {
|
|||
},
|
||||
|
||||
dragStart: function dragStart(aX, aY) {
|
||||
this._xDrag = 0;
|
||||
this._yDrag = 0;
|
||||
this._selectionHelperUI.markerDragStart(this);
|
||||
},
|
||||
|
||||
|
@ -184,7 +191,15 @@ Marker.prototype = {
|
|||
moveBy: function moveBy(aDx, aDy, aClientX, aClientY) {
|
||||
this._xPos -= aDx;
|
||||
this._yPos -= aDy;
|
||||
let direction = (aDx >= 0 && aDy >= 0 ? "start" : "end");
|
||||
this._xDrag -= aDx;
|
||||
this._yDrag -= aDy;
|
||||
// Add a bit of hysteresis to our directional detection so "big fingers"
|
||||
// are detected accurately.
|
||||
let direction = "tbd";
|
||||
if (Math.abs(this._xDrag) > kDragHysteresisDistance ||
|
||||
Math.abs(this._yDrag) > kDragHysteresisDistance) {
|
||||
direction = (this._xDrag <= 0 && this._yDrag <= 0 ? "start" : "end");
|
||||
}
|
||||
// We may swap markers in markerDragMove. If markerDragMove
|
||||
// returns true keep processing, otherwise get out of here.
|
||||
if (this._selectionHelperUI.markerDragMove(this, direction)) {
|
||||
|
@ -973,11 +988,16 @@ var SelectionHelperUI = {
|
|||
|
||||
markerDragMove: function markerDragMove(aMarker, aDirection) {
|
||||
if (aMarker.tag == "caret") {
|
||||
// We are going to transition from caret browsing mode to selection
|
||||
// mode on drag. So swap the caret monocle for a start or end monocle
|
||||
// depending on the direction of the drag, and start selecting text.
|
||||
this._transitionFromCaretToSelection(aDirection);
|
||||
return false;
|
||||
// If direction is "tbd" the drag monocle hasn't determined which
|
||||
// direction the user is dragging.
|
||||
if (aDirection != "tbd") {
|
||||
// We are going to transition from caret browsing mode to selection
|
||||
// mode on drag. So swap the caret monocle for a start or end monocle
|
||||
// depending on the direction of the drag, and start selecting text.
|
||||
this._transitionFromCaretToSelection(aDirection);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
let json = this._getMarkerBaseMessage();
|
||||
json.change = aMarker.tag;
|
||||
|
|
|
@ -875,6 +875,25 @@ setting[type="radio"] > vbox {
|
|||
visibility: collapse;
|
||||
}
|
||||
|
||||
/*Formatting for the limited horizontal space of snapped*/
|
||||
#start-autocomplete[viewstate="snapped"] .richgrid-item-content {
|
||||
-moz-box-orient: horizontal;
|
||||
}
|
||||
|
||||
#start-autocomplete[viewstate="snapped"] {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
#start-container[viewstate="snapped"] {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
#start-container[viewstate="snapped"] .meta-section {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
/* Browser Content Areas ----------------------------------------------------- */
|
||||
|
||||
/* Hide the browser while the start UI is visible */
|
||||
|
|
|
@ -216,6 +216,7 @@
|
|||
background-color: transparent;
|
||||
-moz-margin-end: -3px;
|
||||
position: relative;
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
/* In-tools sidebar */
|
||||
|
|
|
@ -297,3 +297,19 @@
|
|||
#timings-tabpanel .requests-menu-timings-total {
|
||||
transition: transform 0.2s ease-out;
|
||||
}
|
||||
|
||||
/* Responsive sidebar */
|
||||
@media (max-width: 700px) {
|
||||
#details-pane {
|
||||
max-width: none;
|
||||
margin: 0 !important;
|
||||
/* To prevent all the margin hacks to hide the sidebar */
|
||||
}
|
||||
|
||||
.requests-menu-size {
|
||||
border-width: 0px !important;
|
||||
box-shadow: none !important;
|
||||
/* !important are required here because Timeline is not visible and thus
|
||||
the right border and box-shadow of Size column should be hidden */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,6 +230,7 @@
|
|||
width: 3px;
|
||||
-moz-margin-end: -3px;
|
||||
position: relative;
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
/* In-tools sidebar */
|
||||
|
|
|
@ -297,3 +297,19 @@
|
|||
#timings-tabpanel .requests-menu-timings-total {
|
||||
transition: transform 0.2s ease-out;
|
||||
}
|
||||
|
||||
/* Responsive sidebar */
|
||||
@media (max-width: 700px) {
|
||||
#details-pane {
|
||||
max-width: none;
|
||||
margin: 0 !important;
|
||||
/* To prevent all the margin hacks to hide the sidebar */
|
||||
}
|
||||
|
||||
.requests-menu-size {
|
||||
border-width: 0px !important;
|
||||
box-shadow: none !important;
|
||||
/* !important are required here because Timeline is not visible and thus
|
||||
the right border and box-shadow of Size column should be hidden */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,3 +83,31 @@
|
|||
.devtools-autocomplete-listbox.light-theme > richlistitem > label {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* Responsive container */
|
||||
|
||||
.devtools-responsive-container {
|
||||
-moz-box-orient: horizontal;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.devtools-responsive-container {
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
.devtools-responsive-container > .devtools-side-splitter {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
border-top: 1px solid black;
|
||||
min-height: 3px;
|
||||
height: 3px;
|
||||
margin-bottom: -3px;
|
||||
/* In some edge case the cursor is not changed to n-resize */
|
||||
cursor: n-resize;
|
||||
}
|
||||
|
||||
.devtools-responsive-container > .devtools-sidebar-tabs {
|
||||
min-height: 35vh;
|
||||
max-height: 75vh;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,6 +236,7 @@
|
|||
background-color: transparent;
|
||||
-moz-margin-end: -3px;
|
||||
position: relative;
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
/* In-tools sidebar */
|
||||
|
|
|
@ -297,3 +297,19 @@
|
|||
#timings-tabpanel .requests-menu-timings-total {
|
||||
transition: transform 0.2s ease-out;
|
||||
}
|
||||
|
||||
/* Responsive sidebar */
|
||||
@media (max-width: 700px) {
|
||||
#details-pane {
|
||||
max-width: none;
|
||||
margin: 0 !important;
|
||||
/* To prevent all the margin hacks to hide the sidebar */
|
||||
}
|
||||
|
||||
.requests-menu-size {
|
||||
border-width: 0px !important;
|
||||
box-shadow: none !important;
|
||||
/* !important are required here because Timeline is not visible and thus
|
||||
the right border and box-shadow of Size column should be hidden */
|
||||
}
|
||||
}
|
||||
|
|
14
configure.in
14
configure.in
|
@ -2484,8 +2484,6 @@ AC_SUBST(MOZ_LINKER)
|
|||
if test -n "$MOZ_LINKER"; then
|
||||
AC_DEFINE(MOZ_LINKER)
|
||||
fi
|
||||
AC_SUBST(MOZ_ENABLE_SZIP)
|
||||
AC_SUBST(MOZ_SZIP_FLAGS)
|
||||
|
||||
dnl Only one oddball right now (QNX), but this gives us flexibility
|
||||
dnl if any other platforms need to override this in the future.
|
||||
|
@ -4263,6 +4261,7 @@ MOZ_USE_NATIVE_POPUP_WINDOWS=
|
|||
MOZ_ANDROID_HISTORY=
|
||||
MOZ_WEBSMS_BACKEND=
|
||||
MOZ_ANDROID_WALLPAPER=
|
||||
MOZ_ANDROID_BEAM=
|
||||
ACCESSIBILITY=1
|
||||
MOZ_SYS_MSG=
|
||||
MOZ_TIME_MANAGER=
|
||||
|
@ -5146,6 +5145,13 @@ if test -n "$MOZ_ANDROID_WALLPAPER"; then
|
|||
AC_DEFINE(MOZ_ANDROID_WALLPAPER)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable NFC permission on Android
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_ANDROID_BEAM"; then
|
||||
AC_DEFINE(MOZ_ANDROID_BEAM)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Build Personal Security Manager
|
||||
dnl ========================================================
|
||||
|
@ -8594,6 +8600,7 @@ AC_SUBST(MOZ_METRO)
|
|||
AC_SUBST(MOZ_ANDROID_HISTORY)
|
||||
AC_SUBST(MOZ_WEBSMS_BACKEND)
|
||||
AC_SUBST(MOZ_ANDROID_WALLPAPER)
|
||||
AC_SUBST(MOZ_ANDROID_BEAM)
|
||||
AC_SUBST(ENABLE_STRIP)
|
||||
AC_SUBST(PKG_SKIP_STRIP)
|
||||
AC_SUBST(STRIP_FLAGS)
|
||||
|
@ -8907,6 +8914,9 @@ AC_SUBST(LIBJPEG_TURBO_ARM_ASM)
|
|||
AC_SUBST(MOZ_PACKAGE_JSSHELL)
|
||||
AC_SUBST(MOZ_FOLD_LIBS)
|
||||
|
||||
AC_SUBST(MOZ_ENABLE_SZIP)
|
||||
AC_SUBST(MOZ_SZIP_FLAGS)
|
||||
|
||||
AC_MSG_CHECKING([for posix_fallocate])
|
||||
AC_TRY_LINK([#define _XOPEN_SOURCE 600
|
||||
#include <fcntl.h>],
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
conformance/more/conformance/quickCheckAPI-B2.html
|
|
@ -499,6 +499,12 @@ function start() {
|
|||
.split('\n');
|
||||
}
|
||||
|
||||
if (kIsWindows && !kIsWindowsVistaOrHigher) {
|
||||
var testsToSkip = loadTextFileSynchronous('skipped_tests_winxp.txt')
|
||||
.replace(/\r/g, '') // convert to unix line breaks
|
||||
.split('\n');
|
||||
}
|
||||
|
||||
runTestSuite();
|
||||
}
|
||||
|
||||
|
|
|
@ -38,21 +38,19 @@ NS_INTERFACE_MAP_END
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Exported creation functions:
|
||||
|
||||
nsresult
|
||||
NS_NewSVGRect(mozilla::dom::SVGRect** result, float x, float y,
|
||||
float width, float height)
|
||||
already_AddRefed<mozilla::dom::SVGRect>
|
||||
NS_NewSVGRect(float x, float y, float width, float height)
|
||||
{
|
||||
*result = new mozilla::dom::SVGRect(x, y, width, height);
|
||||
if (!*result) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*result);
|
||||
return NS_OK;
|
||||
nsRefPtr<mozilla::dom::SVGRect> rect =
|
||||
new mozilla::dom::SVGRect(x, y, width, height);
|
||||
|
||||
return rect.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewSVGRect(mozilla::dom::SVGRect** result, const gfxRect& rect)
|
||||
already_AddRefed<mozilla::dom::SVGRect>
|
||||
NS_NewSVGRect(const gfxRect& rect)
|
||||
{
|
||||
return NS_NewSVGRect(result,
|
||||
rect.X(), rect.Y(),
|
||||
return NS_NewSVGRect(rect.X(), rect.Y(),
|
||||
rect.Width(), rect.Height());
|
||||
}
|
||||
|
||||
|
|
|
@ -76,12 +76,10 @@ protected:
|
|||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
nsresult
|
||||
NS_NewSVGRect(mozilla::dom::SVGRect** result,
|
||||
float x=0.0f, float y=0.0f,
|
||||
float width=0.0f, float height=0.0f);
|
||||
already_AddRefed<mozilla::dom::SVGRect>
|
||||
NS_NewSVGRect(float x=0.0f, float y=0.0f, float width=0.0f, float height=0.0f);
|
||||
|
||||
nsresult
|
||||
NS_NewSVGRect(mozilla::dom::SVGRect** result, const gfxRect& rect);
|
||||
already_AddRefed<mozilla::dom::SVGRect>
|
||||
NS_NewSVGRect(const gfxRect& rect);
|
||||
|
||||
#endif //mozilla_dom_SVGRect_h
|
||||
|
|
|
@ -411,9 +411,7 @@ SVGSVGElement::CreateSVGMatrix()
|
|||
already_AddRefed<SVGIRect>
|
||||
SVGSVGElement::CreateSVGRect()
|
||||
{
|
||||
nsRefPtr<SVGRect> rect;
|
||||
NS_NewSVGRect(getter_AddRefs(rect));
|
||||
return rect.forget();
|
||||
return NS_NewSVGRect();
|
||||
}
|
||||
|
||||
already_AddRefed<SVGTransform>
|
||||
|
|
|
@ -173,9 +173,7 @@ SVGTransformableElement::GetBBox(ErrorResult& rv)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<SVGRect> rect;
|
||||
rv = NS_NewSVGRect(getter_AddRefs(rect), nsSVGUtils::GetBBox(frame));
|
||||
return rect.forget();
|
||||
return NS_NewSVGRect(nsSVGUtils::GetBBox(frame));
|
||||
}
|
||||
|
||||
already_AddRefed<SVGMatrix>
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "nsDOMString.h"
|
||||
#include "nsStringBuffer.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr member variables
|
||||
|
||||
class nsWrapperCache;
|
||||
|
||||
|
|
|
@ -228,10 +228,6 @@ DOMInterfaces = {
|
|||
'resultNotAddRefed': [ 'delayTime' ],
|
||||
}],
|
||||
|
||||
'DesktopNotificationCenter': {
|
||||
'headerFile': 'mozilla/dom/DesktopNotification.h',
|
||||
},
|
||||
|
||||
'DeviceMotionEvent': {
|
||||
'nativeType': 'nsDOMDeviceMotionEvent',
|
||||
},
|
||||
|
|
|
@ -1786,6 +1786,9 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
|
|||
def definition_body(self):
|
||||
if len(self.descriptor.interface.namedConstructors) > 0:
|
||||
getConstructor = """ JSObject* interfaceObject = GetConstructorObject(aCx, aGlobal);
|
||||
if (!interfaceObject) {
|
||||
return nullptr;
|
||||
}
|
||||
for (unsigned slot = DOM_INTERFACE_SLOTS_BASE; slot < JSCLASS_RESERVED_SLOTS(&InterfaceObjectClass.mBase); ++slot) {
|
||||
JSObject* constructor = &js::GetReservedSlot(interfaceObject, slot).toObject();
|
||||
if (JS_GetFunctionId(JS_GetObjectFunction(constructor)) == JSID_TO_STRING(id)) {
|
||||
|
@ -3720,12 +3723,18 @@ def typeNeedsCx(type, descriptorProvider, retVal=False):
|
|||
if type.isUnion():
|
||||
return any(typeNeedsCx(t, descriptorProvider) for t in
|
||||
type.unroll().flatMemberTypes)
|
||||
if type.isDictionary():
|
||||
return dictionaryNeedsCx(type.inner, descriptorProvider)
|
||||
if retVal and type.isSpiderMonkeyInterface():
|
||||
return True
|
||||
if type.isCallback():
|
||||
return descriptorProvider.workers
|
||||
return type.isAny() or type.isObject()
|
||||
|
||||
def dictionaryNeedsCx(dictionary, descriptorProvider):
|
||||
return (any(typeNeedsCx(m.type, descriptorProvider) for m in dictionary.members) or
|
||||
(dictionary.parent and dictionaryNeedsCx(dictionary.parent, descriptorProvider)))
|
||||
|
||||
# Returns a tuple consisting of a CGThing containing the type of the return
|
||||
# value, or None if there is no need for a return value, and a boolean signaling
|
||||
# whether the return value is passed in an out parameter.
|
||||
|
|
|
@ -226,6 +226,8 @@ class Descriptor(DescriptorProvider):
|
|||
else:
|
||||
if self.workers:
|
||||
headerDefault = "mozilla/dom/workers/bindings/%s.h" % ifaceName
|
||||
elif not self.interface.isExternal() and self.interface.getExtendedAttribute("HeaderFile"):
|
||||
headerDefault = self.interface.getExtendedAttribute("HeaderFile")[0]
|
||||
else:
|
||||
headerDefault = self.nativeType
|
||||
headerDefault = headerDefault.replace("::", "/") + ".h"
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script>
|
||||
HTMLElement.prototype.__proto__ = Proxy.create({}, {});
|
||||
try {
|
||||
window.Image;
|
||||
} finally {
|
||||
// Restore our prototype so the test harnesses can deal with us
|
||||
// We can't just assign to __proto__ because it lives on our proto chain
|
||||
// and we messed that up.
|
||||
var desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
|
||||
desc.set.call(HTMLElement.prototype, Element.prototype);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body></body>
|
||||
</html>
|
|
@ -4,3 +4,4 @@ load 822340-2.html
|
|||
load 832899.html
|
||||
load 860591.html
|
||||
load 860551.html
|
||||
load 862610.html
|
||||
|
|
|
@ -897,7 +897,8 @@ class IDLInterface(IDLObjectWithScope):
|
|||
elif (identifier == "PrefControlled" or
|
||||
identifier == "Pref" or
|
||||
identifier == "NeedNewResolve" or
|
||||
identifier == "JSImplementation"):
|
||||
identifier == "JSImplementation" or
|
||||
identifier == "HeaderFile"):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
else:
|
||||
|
|
|
@ -442,13 +442,13 @@ public:
|
|||
void SetAttributeRenamedTo(int8_t);
|
||||
|
||||
// Dictionary tests
|
||||
void PassDictionary(const Dict&);
|
||||
void ReceiveDictionary(Dict&);
|
||||
void PassDictionary(JSContext*, const Dict&);
|
||||
void ReceiveDictionary(JSContext*, Dict&);
|
||||
void PassOtherDictionary(const GrandparentDict&);
|
||||
void PassSequenceOfDictionaries(const Sequence<Dict>&);
|
||||
void PassDictionaryOrLong(const Dict&);
|
||||
void PassSequenceOfDictionaries(JSContext*, const Sequence<Dict>&);
|
||||
void PassDictionaryOrLong(JSContext*, const Dict&);
|
||||
void PassDictionaryOrLong(int32_t);
|
||||
void PassDictContainingDict(const DictContainingDict&);
|
||||
void PassDictContainingDict(JSContext*, const DictContainingDict&);
|
||||
void PassDictContainingSequence(const DictContainingSequence&);
|
||||
void ReceiveDictContainingSequence(DictContainingSequence&);
|
||||
|
||||
|
@ -468,7 +468,7 @@ public:
|
|||
bool Overload1(TestInterface&);
|
||||
TestInterface* Overload1(const nsAString&, TestInterface&);
|
||||
void Overload2(TestInterface&);
|
||||
void Overload2(const Dict&);
|
||||
void Overload2(JSContext*, const Dict&);
|
||||
void Overload2(const nsAString&);
|
||||
void Overload3(TestInterface&);
|
||||
void Overload3(const TestCallback&);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
interface MozObserver;
|
||||
|
||||
[HeaderFile="mozilla/dom/DesktopNotification.h"]
|
||||
interface DesktopNotificationCenter
|
||||
{
|
||||
[Creator]
|
||||
|
|
|
@ -359,6 +359,7 @@ public:
|
|||
#ifdef MOZ_WIDGET_GONK
|
||||
virtual EGLImage CreateEGLImageForNativeBuffer(void* buffer) = 0;
|
||||
virtual void DestroyEGLImage(EGLImage image) = 0;
|
||||
virtual EGLImage GetNullEGLImage() = 0;
|
||||
#endif
|
||||
|
||||
virtual already_AddRefed<TextureImage>
|
||||
|
|
|
@ -441,6 +441,26 @@ public:
|
|||
{
|
||||
sEGLLibrary.fDestroyImage(EGL_DISPLAY(), image);
|
||||
}
|
||||
|
||||
EGLImage GetNullEGLImage() MOZ_OVERRIDE
|
||||
{
|
||||
if (!mNullGraphicBuffer.get()) {
|
||||
mNullGraphicBuffer
|
||||
= new android::GraphicBuffer(
|
||||
1, 1,
|
||||
PIXEL_FORMAT_RGB_565,
|
||||
GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER);
|
||||
EGLint attrs[] = {
|
||||
LOCAL_EGL_NONE, LOCAL_EGL_NONE
|
||||
};
|
||||
mNullEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(),
|
||||
EGL_NO_CONTEXT,
|
||||
LOCAL_EGL_NATIVE_BUFFER_ANDROID,
|
||||
mNullGraphicBuffer->getNativeBuffer(),
|
||||
attrs);
|
||||
}
|
||||
return mNullEGLImage;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -695,6 +715,8 @@ protected:
|
|||
bool mShareWithEGLImage;
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsRefPtr<HwcComposer2D> mHwc;
|
||||
EGLImage mNullEGLImage;
|
||||
android::sp<android::GraphicBuffer> mNullGraphicBuffer;
|
||||
#endif
|
||||
|
||||
// A dummy texture ID that can be used when we need a texture object whose
|
||||
|
|
|
@ -398,6 +398,38 @@ Layer::SetAnimations(const AnimationArray& aAnimations)
|
|||
Mutated();
|
||||
}
|
||||
|
||||
static uint8_t sPanZoomUserDataKey;
|
||||
struct PanZoomUserData : public LayerUserData {
|
||||
PanZoomUserData(AsyncPanZoomController* aController)
|
||||
: mController(aController)
|
||||
{ }
|
||||
|
||||
// We don't keep a strong ref here because PanZoomUserData is only
|
||||
// set transiently, and APZC is thread-safe refcounted so
|
||||
// AddRef/Release is expensive.
|
||||
AsyncPanZoomController* mController;
|
||||
};
|
||||
|
||||
void
|
||||
Layer::SetAsyncPanZoomController(AsyncPanZoomController *controller)
|
||||
{
|
||||
if (controller) {
|
||||
SetUserData(&sPanZoomUserDataKey, new PanZoomUserData(controller));
|
||||
} else {
|
||||
RemoveUserData(&sPanZoomUserDataKey);
|
||||
}
|
||||
}
|
||||
|
||||
AsyncPanZoomController*
|
||||
Layer::GetAsyncPanZoomController()
|
||||
{
|
||||
LayerUserData* data = GetUserData(&sPanZoomUserDataKey);
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<PanZoomUserData*>(data)->mController;
|
||||
}
|
||||
|
||||
void
|
||||
Layer::ApplyPendingUpdatesToSubtree()
|
||||
{
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace layers {
|
|||
|
||||
class Animation;
|
||||
class AnimationData;
|
||||
class AsyncPanZoomController;
|
||||
class CommonLayerAttributes;
|
||||
class Layer;
|
||||
class ThebesLayer;
|
||||
|
@ -896,6 +897,11 @@ public:
|
|||
const gfx::Margin& GetFixedPositionMargins() { return mMargins; }
|
||||
Layer* GetMaskLayer() { return mMaskLayer; }
|
||||
|
||||
// These functions allow attaching an AsyncPanZoomController to this layer,
|
||||
// and can be used anytime.
|
||||
void SetAsyncPanZoomController(AsyncPanZoomController *controller);
|
||||
AsyncPanZoomController* GetAsyncPanZoomController();
|
||||
|
||||
// Note that all lengths in animation data are either in CSS pixels or app
|
||||
// units and must be converted to device pixels by the compositor.
|
||||
AnimationArray& GetAnimations() { return mAnimations; }
|
||||
|
|
|
@ -159,6 +159,23 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer,
|
|||
return false;
|
||||
}
|
||||
mTextureClient->SetDescriptor(desc);
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
} else if (image->GetFormat() == GONK_IO_SURFACE) {
|
||||
EnsureTextureClient(TEXTURE_SHARED_GL_EXTERNAL);
|
||||
|
||||
nsIntRect rect(0, 0,
|
||||
image->GetSize().width,
|
||||
image->GetSize().height);
|
||||
UpdatePictureRect(rect);
|
||||
|
||||
AutoLockTextureClient lock(mTextureClient);
|
||||
|
||||
SurfaceDescriptor desc = static_cast<GonkIOSurfaceImage*>(image)->GetSurfaceDescriptor();
|
||||
if (!IsSurfaceDescriptorValid(desc)) {
|
||||
return false;
|
||||
}
|
||||
mTextureClient->SetDescriptor(desc);
|
||||
#endif
|
||||
} else {
|
||||
nsRefPtr<gfxASurface> surface = image->GetAsSurface();
|
||||
MOZ_ASSERT(surface);
|
||||
|
|
|
@ -161,7 +161,6 @@ ImageHostBuffered::EnsureTextureHost(TextureIdentifier aTextureId,
|
|||
aTextureInfo);
|
||||
if (result) {
|
||||
mTextureHost->SetBuffer(new SurfaceDescriptor(null_t()), aAllocator);
|
||||
mPictureRect = nsIntRect(0, 0, -1, -1);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -67,18 +67,6 @@ struct LayerTreeState {
|
|||
TargetConfig mTargetConfig;
|
||||
};
|
||||
|
||||
static uint8_t sPanZoomUserDataKey;
|
||||
struct PanZoomUserData : public LayerUserData {
|
||||
PanZoomUserData(AsyncPanZoomController* aController)
|
||||
: mController(aController)
|
||||
{ }
|
||||
|
||||
// We don't keep a strong ref here because PanZoomUserData is only
|
||||
// set transiently, and APZC is thread-safe refcounted so
|
||||
// AddRef/Release is expensive.
|
||||
AsyncPanZoomController* mController;
|
||||
};
|
||||
|
||||
/**
|
||||
* Lookup the indirect shadow tree for |aId| and return it if it
|
||||
* exists. Otherwise null is returned. This must only be called on
|
||||
|
@ -504,12 +492,11 @@ private:
|
|||
if (OP == Resolve) {
|
||||
ref->ConnectReferentLayer(referent);
|
||||
if (AsyncPanZoomController* apzc = state->mController) {
|
||||
referent->SetUserData(&sPanZoomUserDataKey,
|
||||
new PanZoomUserData(apzc));
|
||||
referent->SetAsyncPanZoomController(apzc);
|
||||
}
|
||||
} else {
|
||||
ref->DetachReferentLayer(referent);
|
||||
referent->RemoveUserData(&sPanZoomUserDataKey);
|
||||
referent->SetAsyncPanZoomController(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -855,16 +842,7 @@ CompositorParent::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame,
|
|||
return appliedTransform;
|
||||
}
|
||||
|
||||
AsyncPanZoomController* controller = nullptr;
|
||||
// Check if an AsyncPanZoomController is attached to this layer.
|
||||
if (LayerUserData* data = aLayer->GetUserData(&sPanZoomUserDataKey)) {
|
||||
controller = static_cast<PanZoomUserData*>(data)->mController;
|
||||
} else {
|
||||
// Check if a derived implementation provides a default AsyncPanZoomController.
|
||||
controller = GetDefaultPanZoomController();
|
||||
}
|
||||
|
||||
if (controller) {
|
||||
if (AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController()) {
|
||||
ShadowLayer* shadow = aLayer->AsShadowLayer();
|
||||
|
||||
ViewTransform treeTransform;
|
||||
|
|
|
@ -181,10 +181,6 @@ protected:
|
|||
nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY,
|
||||
gfx::Margin& aFixedLayerMargins);
|
||||
void SetEGLSurfaceSize(int width, int height);
|
||||
// If SetPanZoomControllerForLayerTree is not set, Compositor will use
|
||||
// derived class AsyncPanZoomController transformations.
|
||||
// Compositor will not own AsyncPanZoomController here.
|
||||
virtual AsyncPanZoomController* GetDefaultPanZoomController() { return nullptr; }
|
||||
|
||||
private:
|
||||
void PauseComposition();
|
||||
|
|
|
@ -311,6 +311,16 @@ CompositorOGL::CleanupResources()
|
|||
mGLContext = nullptr;
|
||||
}
|
||||
|
||||
// Impl of a a helper-runnable's "Run" method, used in Initialize()
|
||||
NS_IMETHODIMP
|
||||
CompositorOGL::ReadDrawFPSPref::Run()
|
||||
{
|
||||
// NOTE: This must match the code in Initialize()'s NS_IsMainThread check.
|
||||
Preferences::AddBoolVarCache(&sDrawFPS, "layers.acceleration.draw-fps");
|
||||
Preferences::AddBoolVarCache(&sFrameCounter, "layers.acceleration.frame-counter");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorOGL::Initialize()
|
||||
{
|
||||
|
@ -481,19 +491,11 @@ CompositorOGL::Initialize()
|
|||
}
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
// NOTE: This must match the code in ReadDrawFPSPref::Run().
|
||||
Preferences::AddBoolVarCache(&sDrawFPS, "layers.acceleration.draw-fps");
|
||||
Preferences::AddBoolVarCache(&sFrameCounter, "layers.acceleration.frame-counter");
|
||||
} else {
|
||||
// We have to dispatch an event to the main thread to read the pref.
|
||||
class ReadDrawFPSPref : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
Preferences::AddBoolVarCache(&sDrawFPS, "layers.acceleration.draw-fps");
|
||||
Preferences::AddBoolVarCache(&sFrameCounter, "layers.acceleration.frame-counter");
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
NS_DispatchToMainThread(new ReadDrawFPSPref());
|
||||
}
|
||||
|
||||
|
|
|
@ -141,6 +141,12 @@ private:
|
|||
/** The size of the surface we are rendering to */
|
||||
nsIntSize mSurfaceSize;
|
||||
|
||||
/** Helper-class used by Initialize **/
|
||||
class ReadDrawFPSPref MOZ_FINAL : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
already_AddRefed<mozilla::gl::GLContext> CreateContext();
|
||||
|
||||
/** Shader Programs */
|
||||
|
|
|
@ -593,9 +593,22 @@ SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat)
|
|||
return FORMAT_R5G6B5;
|
||||
case android::PIXEL_FORMAT_A_8:
|
||||
return FORMAT_A8;
|
||||
case 17: // NV21 YUV format, see http://developer.android.com/reference/android/graphics/ImageFormat.html#NV21
|
||||
return FORMAT_B8G8R8A8; // yup, use FORMAT_B8G8R8A8 even though it's a YUV texture. This is an external texture.
|
||||
default:
|
||||
MOZ_NOT_REACHED("Unknown Android pixel format");
|
||||
return FORMAT_B8G8R8A8;
|
||||
return FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static GLenum
|
||||
TextureTargetForAndroidPixelFormat(android::PixelFormat aFormat)
|
||||
{
|
||||
switch (aFormat) {
|
||||
case 17: // NV21 YUV format, see http://developer.android.com/reference/android/graphics/ImageFormat.html#NV21
|
||||
return LOCAL_GL_TEXTURE_EXTERNAL;
|
||||
default:
|
||||
return LOCAL_GL_TEXTURE_2D;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -615,7 +628,7 @@ GrallocTextureHostOGL::DeleteTextures()
|
|||
mGL->MakeCurrent();
|
||||
if (mGLTexture) {
|
||||
mGL->fDeleteTextures(1, &mGLTexture);
|
||||
mGLTexture= 0;
|
||||
mGLTexture = 0;
|
||||
}
|
||||
if (mEGLImage) {
|
||||
mGL->DestroyEGLImage(mEGLImage);
|
||||
|
@ -641,6 +654,7 @@ GrallocTextureHostOGL::SwapTexturesImpl(const SurfaceDescriptor& aImage,
|
|||
const SurfaceDescriptorGralloc& desc = aImage.get_SurfaceDescriptorGralloc();
|
||||
mGraphicBuffer = GrallocBufferActor::GetFrom(desc);
|
||||
mFormat = SurfaceFormatForAndroidPixelFormat(mGraphicBuffer->getPixelFormat());
|
||||
mTextureTarget = TextureTargetForAndroidPixelFormat(mGraphicBuffer->getPixelFormat());
|
||||
|
||||
DeleteTextures();
|
||||
}
|
||||
|
@ -651,7 +665,7 @@ void GrallocTextureHostOGL::BindTexture(GLenum aTextureUnit)
|
|||
|
||||
mGL->MakeCurrent();
|
||||
mGL->fActiveTexture(aTextureUnit);
|
||||
mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mGLTexture);
|
||||
mGL->fBindTexture(mTextureTarget, mGLTexture);
|
||||
mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
}
|
||||
|
||||
|
@ -688,11 +702,11 @@ GrallocTextureHostOGL::Lock()
|
|||
mGL->fGenTextures(1, &mGLTexture);
|
||||
}
|
||||
mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mGLTexture);
|
||||
mGL->fBindTexture(mTextureTarget, mGLTexture);
|
||||
if (!mEGLImage) {
|
||||
mEGLImage = mGL->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer());
|
||||
}
|
||||
mGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, mEGLImage);
|
||||
mGL->fEGLImageTargetTexture2D(mTextureTarget, mEGLImage);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -707,20 +721,11 @@ GrallocTextureHostOGL::Unlock()
|
|||
* the GL may place read locks on it. We must ensure that we release them early enough,
|
||||
* i.e. before the next time that we will try to acquire a write lock on the same buffer,
|
||||
* because read and write locks on gralloc buffers are mutually exclusive.
|
||||
*
|
||||
* Unfortunately there does not seem to exist an EGL function to dissociate a gralloc
|
||||
* buffer from a texture that it was tied to. Failing that, we achieve the same result
|
||||
* by uploading a 1x1 dummy texture image to the same texture, replacing the existing
|
||||
* gralloc buffer attachment.
|
||||
*/
|
||||
mGL->MakeCurrent();
|
||||
mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, mGLTexture);
|
||||
mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0,
|
||||
LOCAL_GL_RGBA,
|
||||
1, 1, 0,
|
||||
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
|
||||
nullptr);
|
||||
mGL->fBindTexture(mTextureTarget, mGLTexture);
|
||||
mGL->fEGLImageTargetTexture2D(mTextureTarget, mGL->GetNullEGLImage());
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat
|
||||
|
|
|
@ -547,6 +547,7 @@ class GrallocTextureHostOGL
|
|||
public:
|
||||
GrallocTextureHostOGL()
|
||||
: mGL(nullptr)
|
||||
, mTextureTarget(0)
|
||||
, mGLTexture(0)
|
||||
, mEGLImage(0)
|
||||
{
|
||||
|
@ -575,6 +576,10 @@ public:
|
|||
|
||||
gl::ShaderProgramType GetShaderProgram() const MOZ_OVERRIDE
|
||||
{
|
||||
if (mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL) {
|
||||
return gl::RGBAExternalLayerProgramType;
|
||||
}
|
||||
MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D);
|
||||
return mFormat == gfx::FORMAT_B8G8R8A8 || mFormat == gfx::FORMAT_B8G8R8X8
|
||||
? gl::BGRALayerProgramType
|
||||
: gl::RGBALayerProgramType;
|
||||
|
@ -605,6 +610,7 @@ private:
|
|||
|
||||
RefPtr<gl::GLContext> mGL;
|
||||
android::sp<android::GraphicBuffer> mGraphicBuffer;
|
||||
GLenum mTextureTarget;
|
||||
GLuint mGLTexture;
|
||||
EGLImage mEGLImage;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.documentElement.offsetHeight;
|
||||
|
||||
var x = document.getElementById('x');
|
||||
x.removeChild(x.childNodes[1]);
|
||||
|
||||
document.documentElement.offsetHeight;
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();">
|
||||
|
||||
<div style="-moz-column-count: 2;"><span style="unicode-bidi: -moz-isolate;" id="x"><span style="direction: rtl;"></span> <span style="unicode-bidi: -moz-isolate; white-space: pre;">
|
||||
x</span></span></div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -368,6 +368,7 @@ load 691118-1.html
|
|||
load 695861.html
|
||||
load 698335.html
|
||||
needs-focus pref(accessibility.browsewithcaret,true) load 699353-1.html
|
||||
load 701504.html
|
||||
load 707098.html
|
||||
load 722137.html
|
||||
load 725535.html
|
||||
|
|
|
@ -199,6 +199,13 @@ struct BidiParagraphData {
|
|||
}
|
||||
}
|
||||
|
||||
void ResetForNewBlock()
|
||||
{
|
||||
for (BidiParagraphData* bpd = this; bpd; bpd = bpd->mSubParagraph) {
|
||||
bpd->mPrevFrame = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AppendFrame(nsIFrame* aFrame,
|
||||
nsBlockInFlowLineIterator* aLineIter,
|
||||
nsIContent* aContent = nullptr)
|
||||
|
@ -603,8 +610,7 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
|
|||
block = static_cast<nsBlockFrame*>(block->GetNextContinuation())) {
|
||||
block->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
|
||||
nsBlockInFlowLineIterator lineIter(block, block->begin_lines());
|
||||
bpd.mPrevFrame = nullptr;
|
||||
bpd.GetSubParagraph()->mPrevFrame = nullptr;
|
||||
bpd.ResetForNewBlock();
|
||||
TraverseFrames(aBlockFrame, &lineIter, block->GetFirstPrincipalChild(), &bpd);
|
||||
// XXX what about overflow lines?
|
||||
}
|
||||
|
@ -920,6 +926,10 @@ nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame,
|
|||
if (!aCurrentFrame)
|
||||
return;
|
||||
|
||||
#ifdef DEBUG
|
||||
nsBlockFrame* initialLineContainer = aLineIter->GetContainer();
|
||||
#endif
|
||||
|
||||
nsIFrame* childFrame = aCurrentFrame;
|
||||
do {
|
||||
/*
|
||||
|
@ -1165,6 +1175,8 @@ nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame,
|
|||
}
|
||||
childFrame = nextSibling;
|
||||
} while (childFrame);
|
||||
|
||||
MOZ_ASSERT(initialLineContainer == aLineIter->GetContainer());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1214,7 +1214,8 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
|
|||
} else {
|
||||
nativeTheme = false;
|
||||
nscoord twipsRadii[8];
|
||||
NS_ASSERTION(aFrameArea.Size() == aForFrame->GetSize(), "unexpected size");
|
||||
NS_ASSERTION(aFrameArea.Size() == aForFrame->VisualBorderRectRelativeToSelf().Size(),
|
||||
"unexpected size");
|
||||
hasBorderRadius = aForFrame->GetBorderRadii(twipsRadii);
|
||||
if (hasBorderRadius) {
|
||||
ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
|
||||
|
|
|
@ -2385,7 +2385,7 @@ void
|
|||
nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) {
|
||||
nsPoint offset = ToReferenceFrame();
|
||||
nsRect borderRect = nsRect(offset, mFrame->GetSize());
|
||||
nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
|
||||
nsPresContext* presContext = mFrame->PresContext();
|
||||
nsAutoTArray<nsRect,10> rects;
|
||||
ComputeDisjointRectangles(mVisibleRegion, &rects);
|
||||
|
|
|
@ -3,9 +3,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// YY need to pass isMultiple before create called
|
||||
|
||||
//#include "nsFormControlFrame.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsLegendFrame.h"
|
||||
#include "nsIDOMNode.h"
|
||||
|
@ -13,7 +11,6 @@
|
|||
#include "nsIDOMHTMLLegendElement.h"
|
||||
#include "nsCSSRendering.h"
|
||||
#include <algorithm>
|
||||
//#include "nsIDOMHTMLCollection.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsISupports.h"
|
||||
|
@ -35,15 +32,12 @@ using namespace mozilla::layout;
|
|||
|
||||
class nsLegendFrame;
|
||||
|
||||
class nsFieldSetFrame : public nsContainerFrame {
|
||||
class nsFieldSetFrame MOZ_FINAL : public nsContainerFrame {
|
||||
public:
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
nsFieldSetFrame(nsStyleContext* aContext);
|
||||
|
||||
NS_IMETHOD SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList);
|
||||
|
||||
NS_HIDDEN_(nscoord)
|
||||
GetIntrinsicWidth(nsRenderingContext* aRenderingContext,
|
||||
nsLayoutUtils::IntrinsicWidthType);
|
||||
|
@ -55,6 +49,21 @@ public:
|
|||
uint32_t aFlags) MOZ_OVERRIDE;
|
||||
virtual nscoord GetBaseline() const;
|
||||
|
||||
/**
|
||||
* The area to paint box-shadows around. It's the border rect except
|
||||
* when there's a <legend> we offset the y-position to the center of it.
|
||||
*/
|
||||
virtual nsRect VisualBorderRectRelativeToSelf() const MOZ_OVERRIDE {
|
||||
nscoord topBorder = StyleBorder()->GetComputedBorderWidth(NS_SIDE_TOP);
|
||||
nsRect r(nsPoint(0,0), GetSize());
|
||||
if (topBorder < mLegendRect.height) {
|
||||
nscoord yoff = (mLegendRect.height - topBorder) / 2;
|
||||
r.y += yoff;
|
||||
r.height -= yoff;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
NS_IMETHOD Reflow(nsPresContext* aPresContext,
|
||||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
|
@ -76,12 +85,20 @@ public:
|
|||
nsIFrame* aOldFrame);
|
||||
|
||||
virtual nsIAtom* GetType() const;
|
||||
virtual bool IsFrameOfType(uint32_t aFlags) const
|
||||
{
|
||||
return nsContainerFrame::IsFrameOfType(aFlags &
|
||||
~nsIFrame::eCanContainOverflowContainers);
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_IMETHOD SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList);
|
||||
|
||||
NS_IMETHOD GetFrameName(nsAString& aResult) const {
|
||||
return MakeFrameName(NS_LITERAL_STRING("FieldSet"), aResult);
|
||||
}
|
||||
|
@ -91,10 +108,40 @@ protected:
|
|||
|
||||
void ReparentFrameList(const nsFrameList& aFrameList);
|
||||
|
||||
// mLegendFrame is a nsLegendFrame or a nsHTMLScrollFrame with the
|
||||
// nsLegendFrame as the scrolled frame (aka content insertion frame).
|
||||
nsIFrame* mLegendFrame;
|
||||
nsIFrame* mContentFrame;
|
||||
/**
|
||||
* Return the anonymous frame that contains all descendants except
|
||||
* the legend frame. This is currently always a block frame with
|
||||
* pseudo nsCSSAnonBoxes::fieldsetContent -- this may change in the
|
||||
* future when we add support for CSS overflow for <fieldset>.
|
||||
*/
|
||||
nsIFrame* GetInner() const
|
||||
{
|
||||
nsIFrame* last = mFrames.LastChild();
|
||||
if (last &&
|
||||
last->StyleContext()->GetPseudo() == nsCSSAnonBoxes::fieldsetContent) {
|
||||
return last;
|
||||
}
|
||||
MOZ_ASSERT(mFrames.LastChild() == mFrames.FirstChild());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the frame that represents the legend if any. This may be
|
||||
* a nsLegendFrame or a nsHTMLScrollFrame with the nsLegendFrame as the
|
||||
* scrolled frame (aka content insertion frame).
|
||||
*/
|
||||
nsIFrame* GetLegend() const
|
||||
{
|
||||
if (mFrames.FirstChild() == GetInner()) {
|
||||
MOZ_ASSERT(mFrames.LastChild() == mFrames.FirstChild());
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(mFrames.FirstChild() &&
|
||||
mFrames.FirstChild()->GetContentInsertionFrame()->GetType() ==
|
||||
nsGkAtoms::legendFrame);
|
||||
return mFrames.FirstChild();
|
||||
}
|
||||
|
||||
nsRect mLegendRect;
|
||||
nscoord mLegendSpace;
|
||||
};
|
||||
|
@ -110,8 +157,6 @@ NS_IMPL_FRAMEARENA_HELPERS(nsFieldSetFrame)
|
|||
nsFieldSetFrame::nsFieldSetFrame(nsStyleContext* aContext)
|
||||
: nsContainerFrame(aContext)
|
||||
{
|
||||
mContentFrame = nullptr;
|
||||
mLegendFrame = nullptr;
|
||||
mLegendSpace = 0;
|
||||
}
|
||||
|
||||
|
@ -121,23 +166,16 @@ nsFieldSetFrame::GetType() const
|
|||
return nsGkAtoms::fieldSetFrame;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_IMETHODIMP
|
||||
nsFieldSetFrame::SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList)
|
||||
{
|
||||
// Get the content and legend frames.
|
||||
if (!aChildList.OnlyChild()) {
|
||||
NS_ASSERTION(aChildList.GetLength() == 2, "Unexpected child list");
|
||||
mContentFrame = aChildList.LastChild();
|
||||
mLegendFrame = aChildList.FirstChild();
|
||||
} else {
|
||||
mContentFrame = aChildList.FirstChild();
|
||||
mLegendFrame = nullptr;
|
||||
}
|
||||
|
||||
// Queue up the frames for the content frame
|
||||
return nsContainerFrame::SetInitialChildList(kPrincipalList, aChildList);
|
||||
nsresult rv = nsContainerFrame::SetInitialChildList(kPrincipalList, aChildList);
|
||||
MOZ_ASSERT(GetInner());
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
class nsDisplayFieldSetBorderBackground : public nsDisplayItem {
|
||||
public:
|
||||
|
@ -185,7 +223,8 @@ nsFieldSetFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
// REVIEW: We don't really need to check frame emptiness here; if it's empty,
|
||||
// the background/border display item won't do anything, and if it isn't empty,
|
||||
// we need to paint the outline
|
||||
if (IsVisibleForPainting(aBuilder)) {
|
||||
if (!(GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) &&
|
||||
IsVisibleForPainting(aBuilder)) {
|
||||
if (StyleBorder()->mBoxShadow) {
|
||||
aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayBoxShadowOuter(aBuilder, this));
|
||||
|
@ -201,27 +240,30 @@ nsFieldSetFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
DO_GLOBAL_REFLOW_COUNT_DSP("nsFieldSetFrame");
|
||||
}
|
||||
|
||||
nsDisplayListCollection contentDisplayItems;
|
||||
if (mContentFrame) {
|
||||
// Collect mContentFrame's display items into their own collection. We need
|
||||
// to be calling BuildDisplayList on mContentFrame before mLegendFrame in
|
||||
// case it contains out-of-flow frames whose placeholders are under
|
||||
// mLegendFrame. However, we want mContentFrame's display items to be
|
||||
// after mLegendFrame's display items in z-order, so we need to save them
|
||||
// and append them later.
|
||||
BuildDisplayListForChild(aBuilder, mContentFrame, aDirtyRect,
|
||||
contentDisplayItems);
|
||||
if (GetPrevInFlow()) {
|
||||
DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
|
||||
}
|
||||
if (mLegendFrame) {
|
||||
|
||||
nsDisplayListCollection contentDisplayItems;
|
||||
if (nsIFrame* inner = GetInner()) {
|
||||
// Collect the inner frame's display items into their own collection.
|
||||
// We need to be calling BuildDisplayList on it before the legend in
|
||||
// case it contains out-of-flow frames whose placeholders are in the
|
||||
// legend. However, we want the inner frame's display items to be
|
||||
// after the legend's display items in z-order, so we need to save them
|
||||
// and append them later.
|
||||
BuildDisplayListForChild(aBuilder, inner, aDirtyRect, contentDisplayItems);
|
||||
}
|
||||
if (nsIFrame* legend = GetLegend()) {
|
||||
// The legend's background goes on our BlockBorderBackgrounds list because
|
||||
// it's a block child.
|
||||
nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds());
|
||||
BuildDisplayListForChild(aBuilder, mLegendFrame, aDirtyRect, set);
|
||||
BuildDisplayListForChild(aBuilder, legend, aDirtyRect, set);
|
||||
}
|
||||
// Put mContentFrame's display items on the master list. Note that
|
||||
// this moves mContentFrame's border/background display items to our
|
||||
// BorderBackground() list, which isn't really correct, but it's OK because
|
||||
// mContentFrame is anonymous and can't have its own border and background.
|
||||
// Put the inner frame's display items on the master list. Note that this
|
||||
// moves its border/background display items to our BorderBackground() list,
|
||||
// which isn't really correct, but it's OK because the inner frame is
|
||||
// anonymous and can't have its own border and background.
|
||||
contentDisplayItems.MoveTo(aLists);
|
||||
}
|
||||
|
||||
|
@ -229,20 +271,14 @@ void
|
|||
nsFieldSetFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext,
|
||||
nsPoint aPt, const nsRect& aDirtyRect, uint32_t aBGFlags)
|
||||
{
|
||||
const nsStyleBorder* borderStyle = StyleBorder();
|
||||
|
||||
nscoord topBorder = borderStyle->GetComputedBorderWidth(NS_SIDE_TOP);
|
||||
nscoord yoff = 0;
|
||||
nsPresContext* presContext = PresContext();
|
||||
|
||||
// if the border is smaller than the legend. Move the border down
|
||||
// to be centered on the legend.
|
||||
// FIXME: This means border-radius clamping is incorrect; we should
|
||||
// override nsIFrame::GetBorderRadii.
|
||||
if (topBorder < mLegendRect.height)
|
||||
yoff = (mLegendRect.height - topBorder)/2;
|
||||
|
||||
nsRect rect(aPt.x, aPt.y + yoff, mRect.width, mRect.height - yoff);
|
||||
nsRect rect = VisualBorderRectRelativeToSelf();
|
||||
nscoord yoff = rect.y;
|
||||
rect += aPt;
|
||||
nsPresContext* presContext = PresContext();
|
||||
|
||||
nsCSSRendering::PaintBackground(presContext, aRenderingContext, this,
|
||||
aDirtyRect, rect, aBGFlags);
|
||||
|
@ -250,11 +286,12 @@ nsFieldSetFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext,
|
|||
nsCSSRendering::PaintBoxShadowInner(presContext, aRenderingContext,
|
||||
this, rect, aDirtyRect);
|
||||
|
||||
if (mLegendFrame) {
|
||||
if (nsIFrame* legend = GetLegend()) {
|
||||
nscoord topBorder = StyleBorder()->GetComputedBorderWidth(NS_SIDE_TOP);
|
||||
|
||||
// Use the rect of the legend frame, not mLegendRect, so we draw our
|
||||
// border under the legend's left and right margins.
|
||||
nsRect legendRect = mLegendFrame->GetRect() + aPt;
|
||||
nsRect legendRect = legend->GetRect() + aPt;
|
||||
|
||||
// we should probably use PaintBorderEdges to do this but for now just use clipping
|
||||
// to achieve the same effect.
|
||||
|
@ -312,16 +349,14 @@ nsFieldSetFrame::GetIntrinsicWidth(nsRenderingContext* aRenderingContext,
|
|||
{
|
||||
nscoord legendWidth = 0;
|
||||
nscoord contentWidth = 0;
|
||||
if (mLegendFrame) {
|
||||
if (nsIFrame* legend = GetLegend()) {
|
||||
legendWidth =
|
||||
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, mLegendFrame,
|
||||
aType);
|
||||
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, legend, aType);
|
||||
}
|
||||
|
||||
if (mContentFrame) {
|
||||
if (nsIFrame* inner = GetInner()) {
|
||||
contentWidth =
|
||||
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, mContentFrame,
|
||||
aType);
|
||||
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner, aType);
|
||||
}
|
||||
|
||||
return std::max(legendWidth, contentWidth);
|
||||
|
@ -386,30 +421,38 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
// Initialize OUT parameter
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
|
||||
//------------ Handle Incremental Reflow -----------------
|
||||
bool reflowContent;
|
||||
bool reflowLegend;
|
||||
nsOverflowAreas ocBounds;
|
||||
nsReflowStatus ocStatus = NS_FRAME_COMPLETE;
|
||||
if (GetPrevInFlow()) {
|
||||
ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0,
|
||||
ocStatus);
|
||||
}
|
||||
|
||||
//------------ Handle Incremental Reflow -----------------
|
||||
bool reflowInner;
|
||||
bool reflowLegend;
|
||||
nsIFrame* legend = GetLegend();
|
||||
nsIFrame* inner = GetInner();
|
||||
if (aReflowState.ShouldReflowAllKids()) {
|
||||
reflowContent = mContentFrame != nullptr;
|
||||
reflowLegend = mLegendFrame != nullptr;
|
||||
reflowInner = inner != nullptr;
|
||||
reflowLegend = legend != nullptr;
|
||||
} else {
|
||||
reflowContent = mContentFrame && NS_SUBTREE_DIRTY(mContentFrame);
|
||||
reflowLegend = mLegendFrame && NS_SUBTREE_DIRTY(mLegendFrame);
|
||||
reflowInner = inner && NS_SUBTREE_DIRTY(inner);
|
||||
reflowLegend = legend && NS_SUBTREE_DIRTY(legend);
|
||||
}
|
||||
|
||||
// We don't allow fieldsets to break vertically. If we did, we'd
|
||||
// need logic here to push and pull overflow frames.
|
||||
nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE);
|
||||
NS_ASSERTION(!mContentFrame ||
|
||||
NS_ASSERTION(!inner ||
|
||||
nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext,
|
||||
mContentFrame,
|
||||
inner,
|
||||
nsLayoutUtils::MIN_WIDTH) <=
|
||||
availSize.width,
|
||||
"Bogus availSize.width; should be bigger");
|
||||
NS_ASSERTION(!mLegendFrame ||
|
||||
NS_ASSERTION(!legend ||
|
||||
nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext,
|
||||
mLegendFrame,
|
||||
legend,
|
||||
nsLayoutUtils::MIN_WIDTH) <=
|
||||
availSize.width,
|
||||
"Bogus availSize.width; should be bigger");
|
||||
|
@ -424,17 +467,17 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
// reflow the legend only if needed
|
||||
if (reflowLegend) {
|
||||
nsHTMLReflowState legendReflowState(aPresContext, aReflowState,
|
||||
mLegendFrame, availSize);
|
||||
legend, availSize);
|
||||
|
||||
nsHTMLReflowMetrics legendDesiredSize;
|
||||
|
||||
ReflowChild(mLegendFrame, aPresContext, legendDesiredSize, legendReflowState,
|
||||
ReflowChild(legend, aPresContext, legendDesiredSize, legendReflowState,
|
||||
0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
|
||||
#ifdef NOISY_REFLOW
|
||||
printf(" returned (%d, %d)\n", legendDesiredSize.width, legendDesiredSize.height);
|
||||
#endif
|
||||
// figure out the legend's rectangle
|
||||
legendMargin = mLegendFrame->GetUsedMargin();
|
||||
legendMargin = legend->GetUsedMargin();
|
||||
mLegendRect.width = legendDesiredSize.width + legendMargin.left + legendMargin.right;
|
||||
mLegendRect.height = legendDesiredSize.height + legendMargin.top + legendMargin.bottom;
|
||||
mLegendRect.x = borderPadding.left;
|
||||
|
@ -451,24 +494,24 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
|
||||
// if the legend space changes then we need to reflow the
|
||||
// content area as well.
|
||||
if (mLegendSpace != oldSpace && mContentFrame) {
|
||||
reflowContent = true;
|
||||
if (mLegendSpace != oldSpace && inner) {
|
||||
reflowInner = true;
|
||||
}
|
||||
|
||||
FinishReflowChild(mLegendFrame, aPresContext, &legendReflowState,
|
||||
FinishReflowChild(legend, aPresContext, &legendReflowState,
|
||||
legendDesiredSize, 0, 0, NS_FRAME_NO_MOVE_FRAME);
|
||||
} else if (!mLegendFrame) {
|
||||
} else if (!legend) {
|
||||
mLegendRect.SetEmpty();
|
||||
mLegendSpace = 0;
|
||||
} else {
|
||||
// mLegendSpace and mLegendRect haven't changed, but we need
|
||||
// the used margin when placing the legend.
|
||||
legendMargin = mLegendFrame->GetUsedMargin();
|
||||
legendMargin = legend->GetUsedMargin();
|
||||
}
|
||||
|
||||
// reflow the content frame only if needed
|
||||
if (reflowContent) {
|
||||
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, mContentFrame,
|
||||
if (reflowInner) {
|
||||
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, inner,
|
||||
availSize);
|
||||
// Our child is "height:100%" but we actually want its height to be reduced
|
||||
// by the amount of content-height the legend is eating up, unless our
|
||||
|
@ -490,19 +533,19 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
NS_ASSERTION(kidReflowState.mComputedMargin == nsMargin(0,0,0,0),
|
||||
"Margins on anonymous fieldset child not supported!");
|
||||
nsPoint pt(borderPadding.left, borderPadding.top + mLegendSpace);
|
||||
ReflowChild(mContentFrame, aPresContext, kidDesiredSize, kidReflowState,
|
||||
ReflowChild(inner, aPresContext, kidDesiredSize, kidReflowState,
|
||||
pt.x, pt.y, 0, aStatus);
|
||||
|
||||
FinishReflowChild(mContentFrame, aPresContext, &kidReflowState,
|
||||
FinishReflowChild(inner, aPresContext, &kidReflowState,
|
||||
kidDesiredSize, pt.x, pt.y, 0);
|
||||
NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus);
|
||||
}
|
||||
|
||||
nsRect contentRect(0,0,0,0);
|
||||
if (mContentFrame) {
|
||||
// We don't support margins on mContentFrame, so our "content rect" is just
|
||||
if (inner) {
|
||||
// We don't support margins on inner, so our "content rect" is just
|
||||
// its rect.
|
||||
contentRect = mContentFrame->GetRect();
|
||||
contentRect = inner->GetRect();
|
||||
}
|
||||
|
||||
// use the computed width if the inner content does not fill it
|
||||
|
@ -510,11 +553,11 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
contentRect.width = aReflowState.ComputedWidth();
|
||||
}
|
||||
|
||||
if (mLegendFrame) {
|
||||
if (legend) {
|
||||
// if the content rect is larger then the legend we can align the legend
|
||||
if (contentRect.width > mLegendRect.width) {
|
||||
int32_t align = static_cast<nsLegendFrame*>
|
||||
(mLegendFrame->GetContentInsertionFrame())->GetAlign();
|
||||
(legend->GetContentInsertionFrame())->GetAlign();
|
||||
|
||||
switch(align) {
|
||||
case NS_STYLE_TEXT_ALIGN_RIGHT:
|
||||
|
@ -534,16 +577,16 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
nsRect actualLegendRect(mLegendRect);
|
||||
actualLegendRect.Deflate(legendMargin);
|
||||
|
||||
nsPoint curOrigin = mLegendFrame->GetPosition();
|
||||
nsPoint curOrigin = legend->GetPosition();
|
||||
|
||||
// only if the origin changed
|
||||
if ((curOrigin.x != mLegendRect.x) || (curOrigin.y != mLegendRect.y)) {
|
||||
mLegendFrame->SetPosition(nsPoint(actualLegendRect.x , actualLegendRect.y));
|
||||
nsContainerFrame::PositionFrameView(mLegendFrame);
|
||||
legend->SetPosition(nsPoint(actualLegendRect.x , actualLegendRect.y));
|
||||
nsContainerFrame::PositionFrameView(legend);
|
||||
|
||||
// We need to recursively process the legend frame's
|
||||
// children since we're moving the frame after Reflow.
|
||||
nsContainerFrame::PositionChildViews(mLegendFrame);
|
||||
nsContainerFrame::PositionChildViews(legend);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,10 +604,15 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
}
|
||||
aDesiredSize.width = contentRect.width + borderPadding.LeftRight();
|
||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
if (mLegendFrame)
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mLegendFrame);
|
||||
if (mContentFrame)
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mContentFrame);
|
||||
if (legend)
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, legend);
|
||||
if (inner)
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inner);
|
||||
|
||||
// Merge overflow container bounds and status.
|
||||
aDesiredSize.mOverflowAreas.UnionWith(ocBounds);
|
||||
NS_MergeReflowStatusInto(&aStatus, ocStatus);
|
||||
|
||||
FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
|
||||
|
||||
InvalidateFrame();
|
||||
|
@ -579,7 +627,7 @@ nsFieldSetFrame::AppendFrames(ChildListID aListID,
|
|||
{
|
||||
// aFrameList is not allowed to contain "the legend" for this fieldset
|
||||
ReparentFrameList(aFrameList);
|
||||
return mContentFrame->AppendFrames(aListID, aFrameList);
|
||||
return GetInner()->AppendFrames(aListID, aFrameList);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -588,15 +636,15 @@ nsFieldSetFrame::InsertFrames(ChildListID aListID,
|
|||
nsFrameList& aFrameList)
|
||||
{
|
||||
NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this ||
|
||||
aPrevFrame->GetParent() == mContentFrame,
|
||||
aPrevFrame->GetParent() == GetInner(),
|
||||
"inserting after sibling frame with different parent");
|
||||
|
||||
// aFrameList is not allowed to contain "the legend" for this fieldset
|
||||
ReparentFrameList(aFrameList);
|
||||
if (MOZ_UNLIKELY(aPrevFrame == mLegendFrame)) {
|
||||
if (MOZ_UNLIKELY(aPrevFrame == GetLegend())) {
|
||||
aPrevFrame = nullptr;
|
||||
}
|
||||
return mContentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
|
||||
return GetInner()->InsertFrames(aListID, aPrevFrame, aFrameList);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -604,8 +652,8 @@ nsFieldSetFrame::RemoveFrame(ChildListID aListID,
|
|||
nsIFrame* aOldFrame)
|
||||
{
|
||||
// For reference, see bug 70648, bug 276104 and bug 236071.
|
||||
NS_ASSERTION(aOldFrame != mLegendFrame, "Cannot remove mLegendFrame here");
|
||||
return mContentFrame->RemoveFrame(aListID, aOldFrame);
|
||||
NS_ASSERTION(aOldFrame != GetLegend(), "Cannot remove legend here");
|
||||
return GetInner()->RemoveFrame(aListID, aOldFrame);
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
|
@ -620,10 +668,11 @@ void
|
|||
nsFieldSetFrame::ReparentFrameList(const nsFrameList& aFrameList)
|
||||
{
|
||||
nsFrameManager* frameManager = PresContext()->FrameManager();
|
||||
nsIFrame* inner = GetInner();
|
||||
for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
|
||||
NS_ASSERTION(mLegendFrame || e.get()->GetType() != nsGkAtoms::legendFrame,
|
||||
NS_ASSERTION(GetLegend() || e.get()->GetType() != nsGkAtoms::legendFrame,
|
||||
"The fieldset's legend is not allowed in this list");
|
||||
e.get()->SetParent(mContentFrame);
|
||||
e.get()->SetParent(inner);
|
||||
frameManager->ReparentStyleContext(e.get());
|
||||
}
|
||||
}
|
||||
|
@ -631,9 +680,9 @@ nsFieldSetFrame::ReparentFrameList(const nsFrameList& aFrameList)
|
|||
nscoord
|
||||
nsFieldSetFrame::GetBaseline() const
|
||||
{
|
||||
// We know mContentFrame is a block, so calling GetBaseline() on it will do
|
||||
// We know inner is a block, so calling GetBaseline() on it will do
|
||||
// the right thing (that being to return the baseline of the last line).
|
||||
NS_ASSERTION(nsLayoutUtils::GetAsBlock(mContentFrame),
|
||||
"Unexpected mContentFrame");
|
||||
return mContentFrame->GetPosition().y + mContentFrame->GetBaseline();
|
||||
nsIFrame* inner = GetInner();
|
||||
NS_ASSERTION(nsLayoutUtils::GetAsBlock(inner), "Unexpected inner");
|
||||
return inner->GetPosition().y + inner->GetBaseline();
|
||||
}
|
||||
|
|
|
@ -433,6 +433,7 @@ load 734777.html
|
|||
test-pref(layout.css.flexbox.enabled,true) load 737313-1.html
|
||||
test-pref(layout.css.flexbox.enabled,true) load 737313-2.html
|
||||
test-pref(layout.css.flexbox.enabled,true) load 737313-3.html
|
||||
test-pref(font.size.inflation.emPerLine,15) asserts(1-100) load font-inflation-762332.html # bug 762332
|
||||
load 762902.html
|
||||
load 762764-1.html
|
||||
load 786740-1.html
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<!DOCTYPE html>
|
||||
<div style="-moz-column-width: 1px; font-family: monospace; width: 2ch;"><div style="position: relative;"><div style="position: absolute;">xxxxxxxxxxxxxx x xxxxxxx x xxxxxxxxxxxxxxxxxx x xxxxxxx x</div></div></div>
|
|
@ -1131,8 +1131,9 @@ public:
|
|||
typedef mozilla::TimeStamp TimeStamp;
|
||||
typedef mozilla::TimeDuration TimeDuration;
|
||||
|
||||
AsyncScroll()
|
||||
AsyncScroll(nsPoint aStartPos)
|
||||
: mIsFirstIteration(true)
|
||||
, mStartPos(aStartPos)
|
||||
, mCallee(nullptr)
|
||||
{}
|
||||
|
||||
|
@ -1143,8 +1144,7 @@ public:
|
|||
nsPoint PositionAt(TimeStamp aTime);
|
||||
nsSize VelocityAt(TimeStamp aTime); // In nscoords per second
|
||||
|
||||
void InitSmoothScroll(TimeStamp aTime, nsPoint aCurrentPos,
|
||||
nsSize aCurrentVelocity, nsPoint aDestination,
|
||||
void InitSmoothScroll(TimeStamp aTime, nsPoint aDestination,
|
||||
nsIAtom *aOrigin, const nsRect& aRange);
|
||||
void Init(const nsRect& aRange) {
|
||||
mRange = aRange;
|
||||
|
@ -1156,12 +1156,12 @@ public:
|
|||
|
||||
TimeStamp mStartTime;
|
||||
|
||||
// mPrevStartTime holds previous 3 timestamps for intervals averaging (to
|
||||
// mPrevEventTime holds previous 3 timestamps for intervals averaging (to
|
||||
// reduce duration fluctuations). When AsyncScroll is constructed and no
|
||||
// previous timestamps are available (indicated with mIsFirstIteration),
|
||||
// initialize mPrevStartTime using imaginary previous timestamps with maximum
|
||||
// initialize mPrevEventTime using imaginary previous timestamps with maximum
|
||||
// relevant intervals between them.
|
||||
TimeStamp mPrevStartTime[3];
|
||||
TimeStamp mPrevEventTime[3];
|
||||
bool mIsFirstIteration;
|
||||
|
||||
// Cached Preferences values to avoid re-reading them when extending an existing
|
||||
|
@ -1200,7 +1200,7 @@ protected:
|
|||
nscoord aCurrentPos, nscoord aCurrentVelocity,
|
||||
nscoord aDestination);
|
||||
|
||||
void InitDuration(nsIAtom *aOrigin);
|
||||
TimeDuration CalcDurationForEventTime(TimeStamp aTime, nsIAtom *aOrigin);
|
||||
|
||||
// The next section is observer/callback management
|
||||
// Bodies of WillRefresh and RefreshDriver contain nsGfxScrollFrameInner specific code.
|
||||
|
@ -1266,11 +1266,12 @@ nsGfxScrollFrameInner::AsyncScroll::VelocityAt(TimeStamp aTime) {
|
|||
}
|
||||
|
||||
/*
|
||||
* Calculate/update mDuration, possibly dynamically according to events rate and event origin.
|
||||
* Calculate duration, possibly dynamically according to events rate and event origin.
|
||||
* (also maintain previous timestamps - which are only used here).
|
||||
*/
|
||||
void
|
||||
nsGfxScrollFrameInner::AsyncScroll::InitDuration(nsIAtom *aOrigin) {
|
||||
TimeDuration
|
||||
nsGfxScrollFrameInner::
|
||||
AsyncScroll::CalcDurationForEventTime(TimeStamp aTime, nsIAtom *aOrigin) {
|
||||
if (!aOrigin){
|
||||
aOrigin = nsGkAtoms::other;
|
||||
}
|
||||
|
@ -1314,21 +1315,20 @@ nsGfxScrollFrameInner::AsyncScroll::InitDuration(nsIAtom *aOrigin) {
|
|||
if (mIsFirstIteration) {
|
||||
// Starting a new scroll (i.e. not when extending an existing scroll animation),
|
||||
// create imaginary prev timestamps with maximum relevant intervals between them.
|
||||
mIsFirstIteration = false;
|
||||
|
||||
// Longest relevant interval (which results in maximum duration)
|
||||
TimeDuration maxDelta = TimeDuration::FromMilliseconds(mOriginMaxMS / mIntervalRatio);
|
||||
mPrevStartTime[0] = mStartTime - maxDelta;
|
||||
mPrevStartTime[1] = mPrevStartTime[0] - maxDelta;
|
||||
mPrevStartTime[2] = mPrevStartTime[1] - maxDelta;
|
||||
mPrevEventTime[0] = aTime - maxDelta;
|
||||
mPrevEventTime[1] = mPrevEventTime[0] - maxDelta;
|
||||
mPrevEventTime[2] = mPrevEventTime[1] - maxDelta;
|
||||
}
|
||||
}
|
||||
|
||||
// Average last 3 delta durations (rounding errors up to 2ms are negligible for us)
|
||||
int32_t eventsDeltaMs = (mStartTime - mPrevStartTime[2]).ToMilliseconds() / 3;
|
||||
mPrevStartTime[2] = mPrevStartTime[1];
|
||||
mPrevStartTime[1] = mPrevStartTime[0];
|
||||
mPrevStartTime[0] = mStartTime;
|
||||
int32_t eventsDeltaMs = (aTime - mPrevEventTime[2]).ToMilliseconds() / 3;
|
||||
mPrevEventTime[2] = mPrevEventTime[1];
|
||||
mPrevEventTime[1] = mPrevEventTime[0];
|
||||
mPrevEventTime[0] = aTime;
|
||||
|
||||
// Modulate duration according to events rate (quicker events -> shorter durations).
|
||||
// The desired effect is to use longer duration when scrolling slowly, such that
|
||||
|
@ -1337,23 +1337,36 @@ nsGfxScrollFrameInner::AsyncScroll::InitDuration(nsIAtom *aOrigin) {
|
|||
// intervals using the recent 4 timestamps (now + three prev -> 3 intervals).
|
||||
int32_t durationMS = clamped<int32_t>(eventsDeltaMs * mIntervalRatio, mOriginMinMS, mOriginMaxMS);
|
||||
|
||||
mDuration = TimeDuration::FromMilliseconds(durationMS);
|
||||
return TimeDuration::FromMilliseconds(durationMS);
|
||||
}
|
||||
|
||||
void
|
||||
nsGfxScrollFrameInner::AsyncScroll::InitSmoothScroll(TimeStamp aTime,
|
||||
nsPoint aCurrentPos,
|
||||
nsSize aCurrentVelocity,
|
||||
nsPoint aDestination,
|
||||
nsIAtom *aOrigin,
|
||||
const nsRect& aRange) {
|
||||
mStartTime = aTime;
|
||||
mStartPos = aCurrentPos;
|
||||
mDestination = aDestination;
|
||||
mRange = aRange;
|
||||
InitDuration(aOrigin);
|
||||
InitTimingFunction(mTimingFunctionX, mStartPos.x, aCurrentVelocity.width, aDestination.x);
|
||||
InitTimingFunction(mTimingFunctionY, mStartPos.y, aCurrentVelocity.height, aDestination.y);
|
||||
TimeDuration duration = CalcDurationForEventTime(aTime, aOrigin);
|
||||
nsSize currentVelocity(0, 0);
|
||||
if (!mIsFirstIteration) {
|
||||
// If an additional event has not changed the destination, then do not let
|
||||
// another minimum duration reset slow things down. If it would then
|
||||
// instead continue with the existing timing function.
|
||||
if (aDestination == mDestination &&
|
||||
aTime + duration > mStartTime + mDuration)
|
||||
return;
|
||||
|
||||
currentVelocity = VelocityAt(aTime);
|
||||
mStartPos = PositionAt(aTime);
|
||||
}
|
||||
mStartTime = aTime;
|
||||
mDuration = duration;
|
||||
mDestination = aDestination;
|
||||
InitTimingFunction(mTimingFunctionX, mStartPos.x, currentVelocity.width,
|
||||
aDestination.x);
|
||||
InitTimingFunction(mTimingFunctionY, mStartPos.y, currentVelocity.height,
|
||||
aDestination.y);
|
||||
mIsFirstIteration = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1590,18 +1603,11 @@ nsGfxScrollFrameInner::ScrollToWithOrigin(nsPoint aScrollPosition,
|
|||
}
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
nsPoint currentPosition = GetScrollPosition();
|
||||
nsSize currentVelocity(0, 0);
|
||||
bool isSmoothScroll = (aMode == nsIScrollableFrame::SMOOTH) &&
|
||||
IsSmoothScrollingEnabled();
|
||||
|
||||
if (mAsyncScroll) {
|
||||
if (mAsyncScroll->mIsSmoothScroll) {
|
||||
currentPosition = mAsyncScroll->PositionAt(now);
|
||||
currentVelocity = mAsyncScroll->VelocityAt(now);
|
||||
}
|
||||
} else {
|
||||
mAsyncScroll = new AsyncScroll;
|
||||
if (!mAsyncScroll) {
|
||||
mAsyncScroll = new AsyncScroll(GetScrollPosition());
|
||||
if (!mAsyncScroll->SetRefreshObserver(this)) {
|
||||
mAsyncScroll = nullptr;
|
||||
// Observer setup failed. Scroll the normal way.
|
||||
|
@ -1616,8 +1622,7 @@ nsGfxScrollFrameInner::ScrollToWithOrigin(nsPoint aScrollPosition,
|
|||
mAsyncScroll->mIsSmoothScroll = isSmoothScroll;
|
||||
|
||||
if (isSmoothScroll) {
|
||||
mAsyncScroll->InitSmoothScroll(now, currentPosition, currentVelocity,
|
||||
mDestination, aOrigin, range);
|
||||
mAsyncScroll->InitSmoothScroll(now, mDestination, aOrigin, range);
|
||||
} else {
|
||||
mAsyncScroll->Init(range);
|
||||
}
|
||||
|
|
|
@ -1008,6 +1008,14 @@ public:
|
|||
nsRect GetContentRect() const;
|
||||
nsRect GetContentRectRelativeToSelf() const;
|
||||
|
||||
/**
|
||||
* The area to paint box-shadows around. The default is the border rect.
|
||||
* (nsFieldSetFrame overrides this).
|
||||
*/
|
||||
virtual nsRect VisualBorderRectRelativeToSelf() const {
|
||||
return nsRect(0, 0, mRect.width, mRect.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size, in app units, of the border radii. It returns FALSE iff all
|
||||
* returned radii == 0 (so no border radii), TRUE otherwise.
|
||||
|
|
|
@ -784,13 +784,11 @@ nsFrameSelection::MoveCaret(uint32_t aKeycode,
|
|||
SetDesiredX(desiredX);
|
||||
}
|
||||
|
||||
int32_t caretStyle =
|
||||
Preferences::GetInt("layout.selection.caret_style", 0);
|
||||
#ifdef XP_MACOSX
|
||||
int32_t caretStyle = Preferences::GetInt("layout.selection.caret_style", 0);
|
||||
if (caretStyle == 0) {
|
||||
caretStyle = 2; // put caret at the selection edge in the |aKeycode| direction
|
||||
// Put caret at the selection edge in the |aKeycode| direction.
|
||||
caretStyle = 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!isCollapsed && !aContinueSelection && caretStyle == 2) {
|
||||
switch (aKeycode){
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче