This commit is contained in:
Ryan VanderMeulen 2013-04-18 10:58:27 -04:00
Родитель c042f794c9 72635c5a76
Коммит bf49d89795
202 изменённых файлов: 4137 добавлений и 2141 удалений

Просмотреть файл

@ -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 */
}
}

Просмотреть файл

@ -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){

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше