Merge mozilla-central to mozilla-inbound

--HG--
extra : rebase_source : 8265ad85fc5376a71af7ed3afe8463b7178286f3
This commit is contained in:
Dorel Luca 2018-08-04 01:08:25 +03:00
Родитель dc2c367d40 9f724d256f
Коммит e10cc6aac4
102 изменённых файлов: 6891 добавлений и 636 удалений

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

@ -176,7 +176,7 @@
<div id="certErrorAndCaptivePortalButtonContainer" class="button-container">
<button id="returnButton" class="primary" autocomplete="off">&returnToPreviousPage1.label;</button>
<button id="openPortalLoginPageButton" class="primary" autocomplete="off">&openPortalLoginPage.label2;</button>
<button id="advancedButton" autocomplete="off">&continue.label;</button>
<button id="advancedButton" autocomplete="off">&continue1.label;</button>
</div>
</div>

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

@ -56,8 +56,6 @@ export default class BasicCardForm extends PaymentStateSubscriberMixin(PaymentRe
let url = "formautofill/editCreditCard.xhtml";
this.promiseReady = this._fetchMarkup(url).then(doc => {
this.form = doc.getElementById("form");
this.form.addEventListener("input", this);
this.form.addEventListener("invalid", this);
return this.form;
});
}
@ -88,6 +86,12 @@ export default class BasicCardForm extends PaymentStateSubscriberMixin(PaymentRe
getAddressLabel: PaymentDialogUtils.getAddressLabel,
});
// The EditCreditCard constructor adds input event listeners on the same element,
// which update field validity. By adding our event listeners after this constructor,
// validity will be updated before our handlers get the event
form.addEventListener("input", this);
form.addEventListener("invalid", this);
let fragment = document.createDocumentFragment();
fragment.append(this.addressAddLink);
fragment.append(" ");

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

@ -300,6 +300,8 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
this.dataset[shippingType + "AddressTitleEdit"];
let addressPickerLabel = this._shippingAddressPicker.dataset[shippingType + "AddressLabel"];
this._shippingAddressPicker.setAttribute("label", addressPickerLabel);
let optionPickerLabel = this._shippingOptionPicker.dataset[shippingType + "OptionsLabel"];
this._shippingOptionPicker.setAttribute("label", optionPickerLabel);
let totalItem = paymentRequest.getTotalItem(state);
let totalAmountEl = this.querySelector("#total > currency-amount");
@ -311,7 +313,13 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
this._header.hidden = !state.page.onboardingWizard && state.page.id != "payment-summary";
this._orderDetailsOverlay.hidden = !state.orderDetailsShowing;
this._errorText.textContent = paymentDetails.error;
let genericError = "";
if (this._shippingAddressPicker.value &&
(!request.paymentDetails.shippingOptions ||
!request.paymentDetails.shippingOptions.length)) {
genericError = this._errorText.dataset[shippingType + "GenericError"];
}
this._errorText.textContent = paymentDetails.error || genericError;
let paymentOptions = request.paymentOptions;
for (let element of this._shippingRelatedEls) {

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

@ -17,6 +17,11 @@
<!ENTITY deliveryAddressLabel "Delivery Address">
<!ENTITY pickupAddressLabel "Pickup Address">
<!ENTITY shippingOptionsLabel "Shipping Options">
<!ENTITY deliveryOptionsLabel "Delivery Options">
<!ENTITY pickupOptionsLabel "Pickup Options">
<!ENTITY shippingGenericError "Can't ship to this address. Select a different address.">
<!ENTITY deliveryGenericError "Can't deliver to this address. Select a different address.">
<!ENTITY pickupGenericError "Can't pick up from this address. Select a different address.">
<!ENTITY paymentMethodsLabel "Payment Method">
<!ENTITY address.addLink.label "Add">
<!ENTITY address.editLink.label "Edit">
@ -100,7 +105,11 @@
<template id="payment-dialog-template">
<header>
<div class="page-error" aria-live="polite"></div>
<div class="page-error"
data-shipping-generic-error="&shippingGenericError;"
data-delivery-generic-error="&deliveryGenericError;"
data-pickup-generic-error="&pickupGenericError;"
aria-live="polite"></div>
<div id="total">
<currency-amount display-code="display-code"></currency-amount>
<div>&header.payTo; <span id="host-name"></span></div>
@ -122,7 +131,9 @@
selected-state-key="selectedShippingAddress"></address-picker>
<shipping-option-picker class="shipping-related"
label="&shippingOptionsLabel;"></shipping-option-picker>
data-shipping-options-label="&shippingOptionsLabel;"
data-delivery-options-label="&deliveryOptionsLabel;"
data-pickup-options-label="&pickupOptionsLabel;"></shipping-option-picker>
<payment-method-picker selected-state-key="selectedPaymentCard"
data-add-link-label="&basicCard.addLink.label;"

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

@ -347,6 +347,53 @@ add_task(async function test_edit() {
form.remove();
});
add_task(async function test_field_validity_updates() {
let form = new BasicCardForm();
form.dataset.updateButtonLabel = "Add";
await form.promiseReady;
display.appendChild(form);
await asyncElementRendered();
let ccNumber = form.form.querySelector("#cc-number");
let nameInput = form.form.querySelector("#cc-name");
info("test with valid cc-number but missing cc-name");
ccNumber.focus();
sendString("4111111111111111");
ok(ccNumber.checkValidity(), "cc-number field is valid with good input");
ok(!nameInput.checkValidity(), "cc-name field is invalid when empty");
ok(form.saveButton.disabled, "Save button should be disabled with incomplete input");
info("correct by adding cc-name value");
nameInput.focus();
sendString("First");
ok(ccNumber.checkValidity(), "cc-number field is valid with good input");
ok(nameInput.checkValidity(), "cc-name field is valid with a value");
ok(!form.saveButton.disabled, "Save button should not be disabled with good input");
info("edit to make the cc-number invalid");
ccNumber.focus();
sendString("aa");
nameInput.focus();
sendString("Surname");
ok(!ccNumber.checkValidity(), "cc-number field becomes invalid with bad input");
ok(nameInput.checkValidity(), "cc-name field is valid with a value");
ok(form.saveButton.disabled, "Save button becomes disabled with bad input");
info("fix the cc-number to make it all valid again");
ccNumber.focus();
sendKey("BACK_SPACE");
sendKey("BACK_SPACE");
info("after backspaces, ccNumber.value: " + ccNumber.value);
ok(ccNumber.checkValidity(), "cc-number field becomes valid with corrected input");
ok(nameInput.checkValidity(), "cc-name field is valid with a value");
ok(!form.saveButton.disabled, "Save button is no longer disabled with corrected input");
form.remove();
});
</script>
</body>

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

@ -144,6 +144,43 @@ add_task(async function test_initial_completeStatus() {
ok(payButton.disabled, "Button is disabled by default");
});
add_task(async function test_generic_errors() {
await setup();
const SHIPPING_GENERIC_ERROR = "Can't ship to that address";
el1._errorText.dataset.shippingGenericError = SHIPPING_GENERIC_ERROR;
el1.requestStore.setState({
savedAddresses: {
"48bnds6854t": {
"address-level1": "MI",
"address-level2": "Some City",
"country": "US",
"guid": "48bnds6854t",
"name": "Mr. Foo",
"postal-code": "90210",
"street-address": "123 Sesame Street,\nApt 40",
"tel": "+1 519 555-5555",
},
"68gjdh354j": {
"address-level1": "CA",
"address-level2": "Mountain View",
"country": "US",
"guid": "68gjdh354j",
"name": "Mrs. Bar",
"postal-code": "94041",
"street-address": "P.O. Box 123",
"tel": "+1 650 555-5555",
},
},
selectedShippingAddress: "48bnds6854t",
});
await asyncElementRendered();
let picker = el1._shippingAddressPicker;
ok(picker.value, "Address picker should have a selected value");
is(el1._errorText.textContent, SHIPPING_GENERIC_ERROR,
"Generic error message should be shown when no shipping options or error are provided");
});
add_task(async function test_processing_completeStatus() {
// "processing": has overlay. Check button visibility
await setup();
@ -234,6 +271,34 @@ add_task(async function test_scrollPaymentRequestPage() {
el1.parentElement.style.height = "";
});
add_task(async function test_picker_labels() {
await setup();
let picker = el1._shippingOptionPicker;
const SHIPPING_OPTIONS_LABEL = "Shipping options";
const DELIVERY_OPTIONS_LABEL = "Delivery options";
const PICKUP_OPTIONS_LABEL = "Pickup options";
picker.dataset.shippingOptionsLabel = SHIPPING_OPTIONS_LABEL;
picker.dataset.deliveryOptionsLabel = DELIVERY_OPTIONS_LABEL;
picker.dataset.pickupOptionsLabel = PICKUP_OPTIONS_LABEL;
for (let [shippingType, label] of [
["shipping", SHIPPING_OPTIONS_LABEL],
["delivery", DELIVERY_OPTIONS_LABEL],
["pickup", PICKUP_OPTIONS_LABEL],
]) {
let request = deepClone(el1.requestStore.getState().request);
request.paymentOptions.requestShipping = true;
request.paymentOptions.shippingType = shippingType;
await el1.requestStore.setState({ request });
await asyncElementRendered();
is(picker.labelElement.textContent, label,
`Label should be appropriate for ${shippingType}`);
info(JSON.stringify(el1.requestStore.getState(), null, 2));
info(picker.outerHTML);
}
});
add_task(async function test_disconnect() {
await setup();

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

@ -10,7 +10,7 @@
<!ENTITY returnToPreviousPage.label "Go Back">
<!ENTITY returnToPreviousPage1.label "Go Back (Recommended)">
<!ENTITY advanced.label "Advanced">
<!ENTITY continue.label "Continue">
<!ENTITY continue1.label "Continue">
<!-- Specific error messages -->

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

@ -800,6 +800,10 @@
box-shadow: inset 4px 0 var(--blue-40);
}
.all-tabs-item[selected]:-moz-locale-dir(rtl) {
box-shadow: inset -4px 0 var(--blue-40);
}
.all-tabs-secondary-button > label {
display: none;
margin: 0 5.5px;

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

@ -667,7 +667,7 @@ static void adjust_eh_frame(ElfSection* eh_frame, unsigned int origAddr, Elf* el
// Decoding of eh_frame based on https://www.airs.com/blog/archives/460
while (size) {
if (size < 2 * sizeof(uint32_t)) goto malformed;
if (size < sizeof(uint32_t)) goto malformed;
serializable<FixedSizeData<uint32_t>> entryLength(data, size, elf->getClass(), elf->getData());
if (!advance_buffer(&data, &size, sizeof(uint32_t))) goto malformed;
@ -675,6 +675,12 @@ static void adjust_eh_frame(ElfSection* eh_frame, unsigned int origAddr, Elf* el
char* cursor = data;
size_t length = entryLength.value;
if (length == 0) {
continue;
}
if (size < sizeof(uint32_t)) goto malformed;
serializable<FixedSizeData<uint32_t>> id(data, size, elf->getClass(), elf->getData());
if (!advance_buffer(&cursor, &length, sizeof(uint32_t))) goto malformed;

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

@ -12,10 +12,16 @@ const { require } = BrowserLoader({
});
const Services = require("Services");
const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
const { createFactory } =
require("devtools/client/shared/vendor/react");
const { render, unmountComponentAtNode } =
require("devtools/client/shared/vendor/react-dom");
const Provider =
createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
const actions = require("./src/actions/index");
const { configureStore } = require("./src/create-store");
const App = createFactory(require("./src/components/App"));
@ -27,7 +33,10 @@ const AboutDebugging = {
return;
}
render(App(), this.mount);
this.store = configureStore();
this.actions = bindActionCreators(actions, this.store.dispatch);
render(Provider({ store: this.store }, App()), this.mount);
},
destroy() {

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

@ -0,0 +1,9 @@
/* 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/. */
"use strict";
const ui = require("./ui");
Object.assign(exports, ui);

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

@ -0,0 +1,8 @@
# 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/.
DevToolsModules(
'index.js',
'ui.js',
)

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

@ -0,0 +1,20 @@
/* 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/. */
"use strict";
const {
PAGE_SELECTED,
} = require("../constants");
function selectPage(page) {
return {
type: PAGE_SELECTED,
page,
};
}
module.exports = {
selectPage,
};

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

@ -4,22 +4,58 @@
"use strict";
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { PAGES } = require("../constants");
const RuntimePage = createFactory(require("./RuntimePage"));
const Sidebar = createFactory(require("./Sidebar"));
class App extends PureComponent {
static get propTypes() {
return {
// The "dispatch" helper is forwarded to the App component via connect.
// From that point, components are responsible for forwarding the dispatch
// property to all components who need to dispatch actions.
dispatch: PropTypes.func.isRequired,
selectedPage: PropTypes.string.isRequired,
};
}
getSelectedPageComponent() {
switch (this.props.selectedPage) {
case PAGES.THIS_FIREFOX:
return RuntimePage();
default:
// Invalid page, blank.
return null;
}
}
render() {
const { dispatch, selectedPage } = this.props;
return dom.div(
{
className: "app",
},
Sidebar(),
RuntimePage(),
Sidebar({ dispatch, selectedPage }),
this.getSelectedPageComponent(),
);
}
}
module.exports = App;
const mapStateToProps = state => {
return {
selectedPage: state.ui.selectedPage,
};
};
const mapDispatchToProps = dispatch => ({
dispatch,
});
module.exports = connect(mapStateToProps, mapDispatchToProps)(App);

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

@ -6,23 +6,44 @@
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { PAGES } = require("../constants");
const SidebarItem = createFactory(require("./SidebarItem"));
const FIREFOX_ICON = "chrome://devtools/skin/images/firefox-logo-glyph.svg";
const MOBILE_ICON = "chrome://devtools/skin/images/firefox-logo-glyph.svg";
class Sidebar extends PureComponent {
static get propTypes() {
return {
dispatch: PropTypes.func.isRequired,
selectedPage: PropTypes.string.isRequired,
};
}
render() {
return dom.section(
const { dispatch, selectedPage } = this.props;
return dom.aside(
{
className: "sidebar",
},
dom.ul(
{},
SidebarItem({
id: PAGES.THIS_FIREFOX,
dispatch,
icon: FIREFOX_ICON,
isSelected: true,
isSelected: PAGES.THIS_FIREFOX === selectedPage,
name: "This Firefox",
}),
SidebarItem({
id: PAGES.CONNECT,
dispatch,
icon: MOBILE_ICON,
isSelected: PAGES.CONNECT === selectedPage,
name: "Connect",
})
)
);

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

@ -8,24 +8,33 @@ const { PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const Actions = require("../actions/index");
/**
* This component displays an item of the Sidebar component.
*/
class SidebarItem extends PureComponent {
static get propTypes() {
return {
dispatch: PropTypes.func.isRequired,
icon: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
isSelected: PropTypes.bool.isRequired,
name: PropTypes.string.isRequired,
};
}
onItemClick() {
this.props.dispatch(Actions.selectPage(this.props.id));
}
render() {
const { icon, isSelected, name } = this.props;
return dom.li(
{
className: "sidebar-item" + (isSelected ? " sidebar-item--selected" : ""),
onClick: () => this.onItemClick()
},
dom.img({
className: "sidebar-item__icon" +

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

@ -0,0 +1,17 @@
/* 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/. */
"use strict";
const actionTypes = {
PAGE_SELECTED: "PAGE_SELECTED",
};
const PAGES = {
THIS_FIREFOX: "this-firefox",
CONNECT: "connect",
};
// flatten constants
module.exports = Object.assign({}, { PAGES }, actionTypes);

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

@ -0,0 +1,18 @@
/* 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/. */
"use strict";
const { createStore } = require("devtools/client/shared/vendor/redux");
const rootReducer = require("./reducers/index");
const { UiState } = require("./reducers/ui-state");
exports.configureStore = function() {
const initialState = {
ui: new UiState()
};
return createStore(rootReducer, initialState);
};

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

@ -3,5 +3,12 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'actions',
'components',
'reducers',
]
DevToolsModules(
'constants.js',
'create-store.js',
)

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

@ -0,0 +1,12 @@
/* 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/. */
"use strict";
const { combineReducers } = require("devtools/client/shared/vendor/redux");
const { uiReducer } = require("./ui-state");
module.exports = combineReducers({
ui: uiReducer
});

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

@ -0,0 +1,8 @@
# 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/.
DevToolsModules(
'index.js',
'ui-state.js',
)

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

@ -0,0 +1,33 @@
/* 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/. */
"use strict";
const {
PAGE_SELECTED,
PAGES
} = require("../constants");
function UiState() {
return {
selectedPage: PAGES.THIS_FIREFOX
};
}
function uiReducer(state = UiState(), action) {
switch (action.type) {
case PAGE_SELECTED: {
const { page } = action;
return { selectedPage: page };
}
default:
return state;
}
}
module.exports = {
UiState,
uiReducer,
};

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

@ -36,16 +36,14 @@ add_task(async function() {
info("Click the event icon for the first element");
let onShown = tooltip.once("shown");
EventUtils.synthesizeMouseAtCenter(evHolder1, {},
inspector.markup.doc.defaultView);
EventUtils.synthesizeMouseAtCenter(evHolder1, {}, inspector.markup.win);
await onShown;
info("event tooltip for the first div is shown");
info("Click the event icon for the second element");
const onHidden = tooltip.once("hidden");
let onHidden = tooltip.once("hidden");
onShown = tooltip.once("shown");
EventUtils.synthesizeMouseAtCenter(evHolder2, {},
inspector.markup.doc.defaultView);
EventUtils.synthesizeMouseAtCenter(evHolder2, {}, inspector.markup.win);
await onHidden;
info("previous tooltip hidden");
@ -53,6 +51,21 @@ add_task(async function() {
await onShown;
info("event tooltip for the second div is shown");
info("Check that clicking on evHolder2 again hides the tooltip");
onHidden = tooltip.once("hidden");
EventUtils.synthesizeMouseAtCenter(evHolder2, {}, inspector.markup.win);
await onHidden;
info("Check that the tooltip does not reappear immediately after");
await waitForTime(1000);
is(tooltip.isVisible(), false,
"The tooltip is still hidden after waiting for one second");
info("Open the tooltip on evHolder2 again");
onShown = tooltip.once("shown");
EventUtils.synthesizeMouseAtCenter(evHolder2, {}, inspector.markup.win);
await onShown;
info("Click on the computed view tab");
const onHighlighterHidden = toolbox.once("node-unhighlight");
const onTabComputedViewSelected = inspector.sidebar.once("computedview-selected");

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

@ -101,7 +101,6 @@ MarkupElementContainer.prototype = extend(MarkupContainer.prototype, {
async _buildEventTooltipContent(target) {
const tooltip = this.markup.eventDetailsTooltip;
await tooltip.hide();
const listenerInfo = await this.node.getEventListenerInfo();
@ -114,7 +113,20 @@ MarkupElementContainer.prototype = extend(MarkupContainer.prototype, {
tooltip.once("hidden", () => {
// Enable the image preview tooltip after closing the event details
this.markup._enableImagePreviewTooltip();
// Allow clicks on the event badge to display the event popup again
// (but allow the currently queued click event to run first).
this.markup.win.setTimeout(() => {
if (this.editor._eventBadge) {
this.editor._eventBadge.style.pointerEvents = "auto";
}
}, 0);
});
// Prevent clicks on the event badge to display the event popup again.
if (this.editor._eventBadge) {
this.editor._eventBadge.style.pointerEvents = "none";
}
tooltip.show(target);
},

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

@ -330,6 +330,7 @@ function HTMLTooltip(toolboxDoc, {
this._position = null;
this._onClick = this._onClick.bind(this);
this._onMouseup = this._onMouseup.bind(this);
this._onXulPanelHidden = this._onXulPanelHidden.bind(this);
this._toggle = new TooltipToggle(this);
@ -456,6 +457,7 @@ HTMLTooltip.prototype = {
// Update the top window reference each time in case the host changes.
this.topWindow = this._getTopWindow();
this.topWindow.addEventListener("click", this._onClick, true);
this.topWindow.addEventListener("mouseup", this._onMouseup, true);
this.emit("shown");
}, 0);
},
@ -694,14 +696,21 @@ HTMLTooltip.prototype = {
* Hide the current tooltip. The event "hidden" will be fired when the tooltip
* is hidden.
*/
async hide() {
async hide({ fromMouseup = false } = {}) {
this.doc.defaultView.clearTimeout(this.attachEventsTimer);
if (!this.isVisible()) {
this.emit("hidden");
return;
}
this.topWindow.removeEventListener("click", this._onClick, true);
// If the tooltip is hidden from a mouseup event, wait for a potential click event
// to be consumed before removing event listeners.
if (fromMouseup) {
await new Promise(resolve => this.topWindow.setTimeout(resolve, 0));
}
this.removeEventListeners();
this.container.classList.remove("tooltip-visible");
if (this.useXulWrapper) {
await this._hideXulWrapper();
@ -716,6 +725,11 @@ HTMLTooltip.prototype = {
}
},
removeEventListeners: function() {
this.topWindow.removeEventListener("click", this._onClick, true);
this.topWindow.removeEventListener("mouseup", this._onMouseup, true);
},
/**
* Check if the tooltip is currently displayed.
* @return {Boolean} true if the tooltip is visible
@ -730,6 +744,7 @@ HTMLTooltip.prototype = {
*/
destroy: function() {
this.hide();
this.removeEventListeners();
this.container.remove();
if (this.xulPanelWrapper) {
this.xulPanelWrapper.remove();
@ -766,12 +781,6 @@ HTMLTooltip.prototype = {
return;
}
// If the disable autohide setting is in effect, ignore.
if (Services.prefs.getBoolPref("ui.popup.disable_autohide", false)) {
return;
}
this.hide();
if (this.consumeOutsideClicks && e.button === 0) {
// Consume only left click events (button === 0).
e.preventDefault();
@ -779,6 +788,25 @@ HTMLTooltip.prototype = {
}
},
/**
* Hide the tooltip on mouseup rather than on click because the surrounding markup
* may change on mousedown in a way that prevents a "click" event from being fired.
* If the element that received the mousedown and the mouseup are different, click
* will not be fired.
*/
_onMouseup: function(e) {
if (this._isInTooltipContainer(e.target)) {
return;
}
// If the disable autohide setting is in effect, ignore.
if (Services.prefs.getBoolPref("ui.popup.disable_autohide", false)) {
return;
}
this.hide({ fromMouseup: true });
},
_isInTooltipContainer: function(node) {
// Check if the target is the tooltip arrow.
if (this.arrow && this.arrow === node) {

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

@ -364,6 +364,7 @@ skip-if = verify
[browser_webconsole_strict_mode_errors.js]
[browser_webconsole_string.js]
[browser_webconsole_telemetry_filters_changed.js]
[browser_webconsole_telemetry_jump_to_definition.js]
[browser_webconsole_time_methods.js]
[browser_webconsole_timestamps.js]
[browser_webconsole_trackingprotection_errors.js]

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

@ -0,0 +1,51 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests the jump_to_definition telemetry event.
"use strict";
const TEST_URI = `data:text/html,<meta charset=utf8><script>
function x(){}
console.log("test message", x);
</script>`;
const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
add_task(async function() {
// Let's reset the counts.
Services.telemetry.clearEvents();
// Ensure no events have been logged
const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
ok(!snapshot.parent, "No events have been logged for the main process");
const hud = await openNewTabAndConsole(TEST_URI);
const message = await waitFor(() => findMessage(hud, "test message"));
info("Click on the 'jump to definition' button");
const jumpIcon = message.querySelector(".jump-definition");
jumpIcon.click();
const events = getJumpToDefinitionEventsExtra();
is(events.length, 1, "There was 1 event logged");
const [event] = events;
ok(event.session_id > 0, "There is a valid session_id in the logged event");
});
function getJumpToDefinitionEventsExtra() {
// Retrieve and clear telemetry events.
const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
const events = snapshot.parent.filter(event =>
event[1] === "devtools.main" &&
event[2] === "jump_to_definition" &&
event[3] === "webconsole"
);
// Since we already know we have the correct event, we only return the `extra` field
// that was passed to it (which is event[5] here).
return events.map(event => event[5]);
}

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

@ -4897,19 +4897,6 @@ nsGlobalWindowInner::GetIndexedDB(ErrorResult& aError)
return mIndexedDB;
}
void
nsGlobalWindowInner::AddPendingPromise(mozilla::dom::Promise* aPromise)
{
mPendingPromises.AppendElement(aPromise);
}
void
nsGlobalWindowInner::RemovePendingPromise(mozilla::dom::Promise* aPromise)
{
DebugOnly<bool> foundIt = mPendingPromises.RemoveElement(aPromise);
MOZ_ASSERT(foundIt, "tried to remove a non-existent element from mPendingPromises");
}
//*****************************************************************************
// nsGlobalWindowInner::nsIInterfaceRequestor
//*****************************************************************************

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

@ -1208,10 +1208,6 @@ public:
// Inner windows only.
void UpdateCanvasFocus(bool aFocusChanged, nsIContent* aNewContent);
// See PromiseWindowProxy.h for an explanation.
void AddPendingPromise(mozilla::dom::Promise* aPromise);
void RemovePendingPromise(mozilla::dom::Promise* aPromise);
public:
virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() override;

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

@ -1619,7 +1619,8 @@ GetDirectoryPath(const char *aPath) {
#endif // DEBUG
extern "C" {
void CGSSetDenyWindowServerConnections(bool);
CGError
CGSSetDenyWindowServerConnections(bool);
void CGSShutdownServerConnections();
};
@ -1631,13 +1632,15 @@ StartMacOSContentSandbox()
return false;
}
if (!XRE_UseNativeEventProcessing()) {
if (Preferences::GetBool(
"security.sandbox.content.mac.disconnect-windowserver")) {
// If we've opened a connection to the window server, shut it down now. Forbid
// future connections as well. We do this for sandboxing, but it also ensures
// that the Activity Monitor will not label the content process as "Not
// responding" because it's not running a native event loop. See bug 1384336.
CGSSetDenyWindowServerConnections(true);
CGSShutdownServerConnections();
CGError result = CGSSetDenyWindowServerConnections(true);
MOZ_DIAGNOSTIC_ASSERT(result == kCGErrorSuccess);
}
nsAutoCString appPath, appBinaryPath, appDir;

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

@ -1,54 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/PromiseWindowProxy.h"
#include "nsGlobalWindowInner.h"
#include "nsPIDOMWindow.h"
#include "nsIWeakReference.h"
#include "mozilla/dom/Promise.h"
using namespace mozilla;
using namespace dom;
PromiseWindowProxy::PromiseWindowProxy(nsPIDOMWindowInner* aWindow, Promise* aPromise)
: mPromise(aPromise)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(aWindow && aPromise);
auto* window = nsGlobalWindowInner::Cast(aWindow);
window->GetWeakReference(getter_AddRefs(mWindow));
window->AddPendingPromise(aPromise);
}
PromiseWindowProxy::~PromiseWindowProxy()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsPIDOMWindowInner> window = GetWindow();
if (window && mPromise) {
nsGlobalWindowInner::Cast(window)->RemovePendingPromise(mPromise);
}
}
RefPtr<Promise>
PromiseWindowProxy::Get() const
{
MOZ_ASSERT(NS_IsMainThread());
if (!mPromise) {
return nullptr;
}
RefPtr<Promise> promise(mPromise);
return promise;
}
nsCOMPtr<nsPIDOMWindowInner>
PromiseWindowProxy::GetWindow() const
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow);
return window;
}

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

@ -1,57 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_PromiseWindowProxy_h
#define mozilla_dom_PromiseWindowProxy_h
#include "nsCOMPtr.h"
#include "mozilla/WeakPtr.h"
class nsIWeakReference;
class nsPIDOMWindowInner;
namespace mozilla {
namespace dom {
class Promise;
// When a data structure is waiting to resolve a promise from a
// window, but that data structure is not owned by that window, there
// exists a dilemma:
//
// 1) If the promise is never resolved, and the non-window data
// structure is keeping alive the promise, the promise's window will
// be leaked.
//
// 2) Something has to keep the promise alive from native code in case
// script has dropped all direct references to it, but the promise is
// later resolved.
//
// PromiseWindowProxy solves this dilemma for the non-window data
// structure. It solves (1) by only keeping a weak reference to the
// promise. It solves (2) by adding a strong reference to the promise
// on the window itself. This ensures that as long as both the
// PromiseWindowProxy and the window are still alive that the promise
// will remain alive. This strong reference is cycle collected, so it
// won't cause the window to leak.
class PromiseWindowProxy final
{
public:
PromiseWindowProxy(nsPIDOMWindowInner* aWindow, mozilla::dom::Promise* aPromise);
~PromiseWindowProxy();
RefPtr<Promise> Get() const;
nsCOMPtr<nsPIDOMWindowInner> GetWindow() const;
private:
nsCOMPtr<nsIWeakReference> mWindow;
WeakPtr<Promise> mPromise;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PromiseWindowProxy_h

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

@ -11,14 +11,12 @@ EXPORTS.mozilla.dom += [
'Promise.h',
'PromiseDebugging.h',
'PromiseNativeHandler.h',
'PromiseWindowProxy.h',
'PromiseWorkerProxy.h',
]
UNIFIED_SOURCES += [
'Promise.cpp',
'PromiseDebugging.cpp',
'PromiseWindowProxy.cpp',
]
LOCAL_INCLUDES += [

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

@ -49,7 +49,6 @@
#include "mozilla/dom/Navigator.h"
#include "mozilla/dom/NotificationEvent.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/PromiseWindowProxy.h"
#include "mozilla/dom/Request.h"
#include "mozilla/dom/RootedDictionary.h"
#include "mozilla/dom/TypedArray.h"

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

@ -105,7 +105,7 @@ CreateElementTransaction::DoTransaction()
}
// Only set selection to insertion point if editor gives permission
if (!mEditorBase->GetShouldTxnSetSelection()) {
if (!mEditorBase->AllowsTransactionsToChangeSelection()) {
// Do nothing - DOM range gravity will adjust selection
return NS_OK;
}

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

@ -52,7 +52,7 @@ bool
DeleteNodeTransaction::CanDoIt() const
{
if (NS_WARN_IF(!mNodeToDelete) || NS_WARN_IF(!mEditorBase) ||
!mParentNode || !mEditorBase->IsModifiableNode(mParentNode)) {
!mParentNode || !mEditorBase->IsModifiableNode(*mParentNode)) {
return false;
}
return true;

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

@ -90,20 +90,18 @@ DeleteRangeTransaction::DoTransaction()
return rv;
}
// only set selection to deletion point if editor gives permission
bool bAdjustSelection;
mEditorBase->ShouldTxnSetSelection(&bAdjustSelection);
if (bAdjustSelection) {
RefPtr<Selection> selection = mEditorBase->GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_NULL_POINTER;
}
rv = selection->Collapse(startRef.AsRaw());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!mEditorBase->AllowsTransactionsToChangeSelection()) {
return NS_OK;
}
RefPtr<Selection> selection = mEditorBase->GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_NULL_POINTER;
}
rv = selection->Collapse(startRef.AsRaw());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// else do nothing - dom range gravity will adjust selection
return NS_OK;
}

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

@ -112,7 +112,7 @@ DeleteTextTransaction::CanDoIt() const
if (NS_WARN_IF(!mCharData) || NS_WARN_IF(!mEditorBase)) {
return false;
}
return mEditorBase->IsModifiableNode(mCharData);
return mEditorBase->IsModifiableNode(*mCharData);
}
NS_IMETHODIMP
@ -137,19 +137,19 @@ DeleteTextTransaction::DoTransaction()
mEditorBase->RangeUpdaterRef().
SelAdjDeleteText(mCharData, mOffset, mLengthToDelete);
// Only set selection to deletion point if editor gives permission
if (mEditorBase->GetShouldTxnSetSelection()) {
RefPtr<Selection> selection = mEditorBase->GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
ErrorResult error;
selection->Collapse(EditorRawDOMPoint(mCharData, mOffset), error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
if (!mEditorBase->AllowsTransactionsToChangeSelection()) {
return NS_OK;
}
RefPtr<Selection> selection = mEditorBase->GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
ErrorResult error;
selection->Collapse(EditorRawDOMPoint(mCharData, mOffset), error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
// Else do nothing - DOM Range gravity will adjust selection
return NS_OK;
}

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

@ -163,7 +163,7 @@ EditorBase::EditorBase()
, mDirection(eNone)
, mDocDirtyState(-1)
, mSpellcheckCheckboxState(eTriUnset)
, mShouldTxnSetSelection(true)
, mAllowsTransactionsToChangeSelection(true)
, mDidPreDestroy(false)
, mDidPostCreate(false)
, mDispatchInputEvent(true)
@ -982,18 +982,10 @@ EditorBase::EndPlaceholderTransaction()
mPlaceholderBatch--;
}
NS_IMETHODIMP
EditorBase::ShouldTxnSetSelection(bool* aResult)
{
NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
*aResult = mShouldTxnSetSelection;
return NS_OK;
}
NS_IMETHODIMP
EditorBase::SetShouldTxnSetSelection(bool aShould)
{
mShouldTxnSetSelection = aShould;
MakeThisAllowTransactionsToChangeSelection(aShould);
return NS_OK;
}
@ -1732,7 +1724,7 @@ EditorBase::ReplaceContainerWithTransactionInternal(
AutoReplaceContainerSelNotify selStateNotify(mRangeUpdater, &aOldContainer,
newContainer);
{
AutoTransactionsConserveSelection conserveSelection(this);
AutoTransactionsConserveSelection conserveSelection(*this);
// Move all children from the old container to the new container.
while (aOldContainer.HasChildren()) {
nsCOMPtr<nsIContent> child = aOldContainer.GetFirstChild();
@ -1861,7 +1853,7 @@ EditorBase::InsertContainerWithTransactionInternal(
}
{
AutoTransactionsConserveSelection conserveSelection(this);
AutoTransactionsConserveSelection conserveSelection(*this);
rv = InsertNodeWithTransaction(aContent,
EditorRawDOMPoint(newContainer, 0));
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -2661,9 +2653,10 @@ EditorBase::InsertTextWithTransaction(
const EditorRawDOMPoint& aPointToInsert,
EditorRawDOMPoint* aPointAfterInsertedString)
{
// NOTE: caller *must* have already used AutoTransactionsConserveSelection
// stack-based class to turn off txn selection updating. Caller also turned
// on rules sniffing if desired.
MOZ_ASSERT(ShouldHandleIMEComposition() ||
!AllowsTransactionsToChangeSelection(),
"caller must have already used AutoTransactionsConserveSelection "
"if this is not for updating composition string");
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
return NS_ERROR_INVALID_ARG;
@ -3162,7 +3155,8 @@ EditorBase::DoSplitNode(const EditorDOMPoint& aStartOfRightNode,
NS_WARNING_ASSERTION(!Destroyed(),
"The editor is destroyed during splitting a node");
bool shouldSetSelection = GetShouldTxnSetSelection();
bool allowedTransactionsToChangeSelection =
AllowsTransactionsToChangeSelection();
RefPtr<Selection> previousSelection;
for (size_t i = 0; i < savedRanges.Length(); ++i) {
@ -3180,8 +3174,8 @@ EditorBase::DoSplitNode(const EditorDOMPoint& aStartOfRightNode,
// XXX Looks like that we don't need to modify normal selection here
// because selection will be modified by the caller if
// GetShouldTxnSetSelection() will return true.
if (shouldSetSelection &&
// AllowsTransactionsToChangeSelection() will return true.
if (allowedTransactionsToChangeSelection &&
range.mSelection->Type() == SelectionType::eNormal) {
// If the editor should adjust the selection, don't bother restoring
// the ranges for the normal selection here.
@ -3320,7 +3314,8 @@ EditorBase::DoJoinNodes(nsINode* aNodeToKeep,
ErrorResult err;
aParent->RemoveChild(*aNodeToJoin, err);
bool shouldSetSelection = GetShouldTxnSetSelection();
bool allowedTransactionsToChangeSelection =
AllowsTransactionsToChangeSelection();
RefPtr<Selection> previousSelection;
for (size_t i = 0; i < savedRanges.Length(); ++i) {
@ -3337,7 +3332,7 @@ EditorBase::DoJoinNodes(nsINode* aNodeToKeep,
previousSelection = range.mSelection;
}
if (shouldSetSelection &&
if (allowedTransactionsToChangeSelection &&
range.mSelection->Type() == SelectionType::eNormal) {
// If the editor should adjust the selection, don't bother restoring
// the ranges for the normal selection here.
@ -3372,10 +3367,12 @@ EditorBase::DoJoinNodes(nsINode* aNodeToKeep,
}
}
if (shouldSetSelection) {
if (allowedTransactionsToChangeSelection) {
// Editor wants us to set selection at join point.
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
selection->Collapse(aNodeToKeep, AssertedCast<int32_t>(firstNodeLength));
}
@ -4162,12 +4159,6 @@ EditorBase::EndUpdateViewBatch()
return NS_OK;
}
bool
EditorBase::GetShouldTxnSetSelection()
{
return mShouldTxnSetSelection;
}
TextComposition*
EditorBase::GetComposition() const
{
@ -4963,9 +4954,9 @@ EditorBase::SetTextDirectionTo(TextDirection aTextDirection)
}
bool
EditorBase::IsModifiableNode(nsINode* aNode)
EditorBase::IsModifiableNode(const nsINode& aNode) const
{
return true;
return !AsHTMLEditor() || aNode.IsEditable();
}
nsIContent*

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

@ -60,6 +60,7 @@ class CompositionTransaction;
class CreateElementTransaction;
class CSSEditUtils;
class DeleteNodeTransaction;
class DeleteRangeTransaction;
class DeleteTextTransaction;
class EditAggregateTransaction;
class EditorEventListener;
@ -1440,10 +1441,12 @@ protected: // May be called by friends.
*/
bool IsEditable(nsINode* aNode)
{
NS_ENSURE_TRUE(aNode, false);
if (NS_WARN_IF(!aNode)) {
return false;
}
if (!aNode->IsContent() || IsMozEditorBogusNode(aNode) ||
!IsModifiableNode(aNode)) {
!IsModifiableNode(*aNode)) {
return false;
}
@ -1510,7 +1513,10 @@ protected: // May be called by friends.
return aNode->NodeType() == nsINode::TEXT_NODE;
}
virtual bool IsModifiableNode(nsINode* aNode);
/**
* IsModifiableNode() checks whether the node is editable or not.
*/
bool IsModifiableNode(const nsINode& aNode) const;
/**
* GetNodeAtRangeOffsetPoint() returns the node at this position in a range,
@ -1545,7 +1551,25 @@ protected: // May be called by friends.
static bool IsPreformatted(nsINode* aNode);
bool GetShouldTxnSetSelection();
/**
* AllowsTransactionsToChangeSelection() returns true if editor allows any
* transactions to change Selection. Otherwise, transactions shouldn't
* change Selection.
*/
inline bool AllowsTransactionsToChangeSelection() const
{
return mAllowsTransactionsToChangeSelection;
}
/**
* MakeThisAllowTransactionsToChangeSelection() with true makes this editor
* allow transactions to change Selection. Otherwise, i.e., with false,
* makes this editor not allow transactions to change Selection.
*/
inline void MakeThisAllowTransactionsToChangeSelection(bool aAllow)
{
mAllowsTransactionsToChangeSelection = aAllow;
}
nsresult HandleInlineSpellCheck(EditSubAction aEditSubAction,
Selection& aSelection,
@ -1946,8 +1970,9 @@ protected:
// A Tristate value.
uint8_t mSpellcheckCheckboxState;
// Turn off for conservative selection adjustment by transactions.
bool mShouldTxnSetSelection;
// If false, transactions should not change Selection even after modifying
// the DOM tree.
bool mAllowsTransactionsToChangeSelection;
// Whether PreDestroy has been called.
bool mDidPreDestroy;
// Whether PostCreate has been called.
@ -1971,6 +1996,7 @@ protected:
friend class CreateElementTransaction;
friend class CSSEditUtils;
friend class DeleteNodeTransaction;
friend class DeleteRangeTransaction;
friend class DeleteTextTransaction;
friend class HTMLEditRules;
friend class HTMLEditUtils;

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

@ -572,28 +572,25 @@ protected:
class MOZ_RAII AutoTransactionsConserveSelection final
{
public:
explicit AutoTransactionsConserveSelection(EditorBase* aEditorBase
explicit AutoTransactionsConserveSelection(EditorBase& aEditorBase
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mEditorBase(aEditorBase)
, mOldState(true)
, mAllowedTransactionsToChangeSelection(
aEditorBase.AllowsTransactionsToChangeSelection())
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mEditorBase) {
mOldState = mEditorBase->GetShouldTxnSetSelection();
mEditorBase->SetShouldTxnSetSelection(false);
}
mEditorBase.MakeThisAllowTransactionsToChangeSelection(false);
}
~AutoTransactionsConserveSelection()
{
if (mEditorBase) {
mEditorBase->SetShouldTxnSetSelection(mOldState);
}
mEditorBase.MakeThisAllowTransactionsToChangeSelection(
mAllowedTransactionsToChangeSelection);
}
protected:
EditorBase* mEditorBase;
bool mOldState;
EditorBase& mEditorBase;
bool mAllowedTransactionsToChangeSelection;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};

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

@ -378,7 +378,7 @@ HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
nsIContent* hostContent = GetActiveEditingHost();
if (mIsObjectResizingEnabled && focusElement &&
IsModifiableNode(focusElement) && focusElement != hostContent) {
IsModifiableNode(*focusElement) && focusElement != hostContent) {
if (nsGkAtoms::img == focusTagAtom) {
mResizedObjectIsAnImage = true;
}
@ -396,7 +396,7 @@ HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
}
if (mIsAbsolutelyPositioningEnabled && absPosElement &&
IsModifiableNode(absPosElement) && absPosElement != hostContent) {
IsModifiableNode(*absPosElement) && absPosElement != hostContent) {
if (mAbsolutelyPositionedObject) {
nsresult rv = RefreshGrabber();
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -411,7 +411,7 @@ HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
}
if (mIsInlineTableEditingEnabled && cellElement &&
IsModifiableNode(cellElement) && cellElement != hostContent) {
IsModifiableNode(*cellElement) && cellElement != hostContent) {
if (mInlineEditedCell) {
nsresult rv = RefreshInlineTableEditingUI();
if (NS_WARN_IF(NS_FAILED(rv))) {

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

@ -491,7 +491,7 @@ HTMLEditRules::AfterEditInner(EditSubAction aEditSubAction,
(aEditSubAction == EditSubAction::eRedo))) {
// don't let any txns in here move the selection around behind our back.
// Note that this won't prevent explicit selection setting from working.
AutoTransactionsConserveSelection dontChangeMySelection(&HTMLEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
// expand the "changed doc range" as needed
PromoteRange(*mDocChangeRange, aEditSubAction);
@ -660,22 +660,31 @@ HTMLEditRules::WillDoAction(Selection* aSelection,
RefPtr<nsRange> range = SelectionRef().GetRangeAt(0);
nsCOMPtr<nsINode> selStartNode = range->GetStartContainer();
if (NS_WARN_IF(!selStartNode)) {
return NS_ERROR_FAILURE;
}
if (!HTMLEditorRef().IsModifiableNode(selStartNode)) {
if (!HTMLEditorRef().IsModifiableNode(*selStartNode)) {
*aCancel = true;
return NS_OK;
}
nsCOMPtr<nsINode> selEndNode = range->GetEndContainer();
if (NS_WARN_IF(!selEndNode)) {
return NS_ERROR_FAILURE;
}
if (selStartNode != selEndNode) {
if (!HTMLEditorRef().IsModifiableNode(selEndNode)) {
if (!HTMLEditorRef().IsModifiableNode(*selEndNode)) {
*aCancel = true;
return NS_OK;
}
NS_ENSURE_STATE(mHTMLEditor);
if (!HTMLEditorRef().IsModifiableNode(range->GetCommonAncestor())) {
nsINode* commonAncestor = range->GetCommonAncestor();
if (NS_WARN_IF(!commonAncestor)) {
return NS_ERROR_FAILURE;
}
if (!HTMLEditorRef().IsModifiableNode(*commonAncestor)) {
*aCancel = true;
return NS_OK;
}
@ -1449,7 +1458,7 @@ HTMLEditRules::WillInsertText(EditSubAction aEditSubAction,
AutoLockListener lockit(&mListenerEnabled);
// don't change my selection in subtransactions
AutoTransactionsConserveSelection dontChangeMySelection(&HTMLEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
nsAutoString tString(*inString);
const char16_t *unicodeBuf = tString.get();
int32_t pos = 0;
@ -1749,7 +1758,7 @@ HTMLEditRules::WillInsertBreak(bool* aCancel,
MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
// Do nothing if the node is read-only
if (!HTMLEditorRef().IsModifiableNode(atStartOfSelection.GetContainer())) {
if (!HTMLEditorRef().IsModifiableNode(*atStartOfSelection.GetContainer())) {
*aCancel = true;
return NS_OK;
}
@ -2967,7 +2976,7 @@ HTMLEditRules::WillDeleteSelection(nsIEditor::EDirection aAction,
// Figure out if the endpoints are in nodes that can be merged. Adjust
// surrounding whitespace in preparation to delete selection.
if (!IsPlaintextEditor()) {
AutoTransactionsConserveSelection dontChangeMySelection(&HTMLEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
rv = WSRunObject::PrepareToDeleteRange(&HTMLEditorRef(),
address_of(startNode), &startOffset,
address_of(endNode), &endOffset);
@ -3383,7 +3392,7 @@ HTMLEditRules::TryToJoinBlocksWithTransaction(nsIContent& aLeftNode,
}
}
AutoTransactionsConserveSelection dontChangeMySelection(&HTMLEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
// offset below is where you find yourself in rightBlock when you traverse
// upwards from leftBlock
@ -4506,7 +4515,7 @@ HTMLEditRules::MakeBasicBlock(nsAtom& blockType)
}
AutoSelectionRestorer selectionRestorer(&SelectionRef(), &HTMLEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(&HTMLEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
// Contruct a list of nodes to act on.
nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
@ -5921,7 +5930,7 @@ HTMLEditRules::CreateStyleForInsertText(nsIDocument& aDocument)
{
// Transactions may set selection, but we will set selection if necessary.
AutoTransactionsConserveSelection dontChangeMySelection(&HTMLEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
while (item && node != rootElement) {
// XXX If we redesign ClearStyle(), we can use EditorDOMPoint in this
@ -7548,7 +7557,7 @@ HTMLEditRules::GetListActionNodes(
{
// We don't like other people messing with our selection!
AutoTransactionsConserveSelection dontChangeMySelection(&HTMLEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
// contruct a list of nodes to act on.
nsresult rv = GetNodesFromSelection(EditSubAction::eCreateOrChangeList,

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

@ -3190,7 +3190,7 @@ HTMLEditor::DeleteNodeWithTransaction(nsINode& aNode)
// Do nothing if the node is read-only.
// XXX This is not a override method of EditorBase's method. This might
// cause not called accidentally. We need to investigate this issue.
if (NS_WARN_IF(!IsModifiableNode(aNode.AsContent()) &&
if (NS_WARN_IF(!IsModifiableNode(*aNode.AsContent()) &&
!IsMozEditorBogusNode(aNode.AsContent()))) {
return NS_ERROR_FAILURE;
}
@ -3220,7 +3220,7 @@ HTMLEditor::DeleteTextWithTransaction(CharacterData& aCharData,
uint32_t aLength)
{
// Do nothing if the node is read-only
if (!IsModifiableNode(&aCharData)) {
if (!IsModifiableNode(aCharData)) {
return NS_ERROR_FAILURE;
}
@ -3239,7 +3239,7 @@ HTMLEditor::InsertTextWithTransaction(
}
// Do nothing if the node is read-only
if (!IsModifiableNode(aPointToInsert.GetContainer())) {
if (!IsModifiableNode(*aPointToInsert.GetContainer())) {
return NS_ERROR_FAILURE;
}
@ -3358,12 +3358,6 @@ HTMLEditor::ContentRemoved(nsIContent* aChild,
}
}
bool
HTMLEditor::IsModifiableNode(nsINode* aNode)
{
return !aNode || aNode->IsEditable();
}
NS_IMETHODIMP
HTMLEditor::DebugUnitTests(int32_t* outNumTests,
int32_t* outNumTestsFailed)
@ -3612,7 +3606,7 @@ nsresult
HTMLEditor::CollapseAdjacentTextNodes(nsRange* aInRange)
{
NS_ENSURE_TRUE(aInRange, NS_ERROR_NULL_POINTER);
AutoTransactionsConserveSelection dontChangeMySelection(this);
AutoTransactionsConserveSelection dontChangeMySelection(*this);
nsTArray<nsCOMPtr<nsINode>> textNodes;
// we can't actually do anything during iteration, so store the text nodes in an array
// don't bother ref counting them because we know we can hold them for the
@ -4276,7 +4270,7 @@ HTMLEditor::SetCSSBackgroundColorWithTransaction(const nsAString& aColor)
*this, EditSubAction::eInsertElement,
nsIEditor::eNext);
AutoSelectionRestorer selectionRestorer(selection, this);
AutoTransactionsConserveSelection dontChangeMySelection(this);
AutoTransactionsConserveSelection dontChangeMySelection(*this);
// XXX Although, this method may set background color of ancestor block
// element, using EditSubAction::eSetTextProperty.

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

@ -447,8 +447,6 @@ protected: // May be called by friends.
nsresult RelativeChangeElementZIndex(Element& aElement, int32_t aChange,
int32_t* aReturn);
virtual bool IsModifiableNode(nsINode* aNode) override;
virtual bool IsBlockNode(nsINode *aNode) override;
using EditorBase::IsBlockNode;

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

@ -1111,7 +1111,7 @@ HTMLEditor::InsertFromTransferable(nsITransferable* transferable,
transferable->GetAnyTransferData(bestFlavor,
getter_AddRefs(genericDataObj),
&len))) {
AutoTransactionsConserveSelection dontChangeMySelection(this);
AutoTransactionsConserveSelection dontChangeMySelection(*this);
nsAutoString flavor;
CopyASCIItoUTF16(bestFlavor, flavor);
nsAutoString stuffToPaste;

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

@ -89,7 +89,7 @@ HTMLEditor::SetInlineProperty(nsAtom* aProperty,
*this, EditSubAction::eInsertElement,
nsIEditor::eNext);
AutoSelectionRestorer selectionRestorer(selection, this);
AutoTransactionsConserveSelection dontChangeMySelection(this);
AutoTransactionsConserveSelection dontChangeMySelection(*this);
bool cancel, handled;
EditSubActionInfo subActionInfo(EditSubAction::eSetTextProperty);
@ -1244,7 +1244,7 @@ HTMLEditor::RemoveInlineProperty(nsAtom* aProperty,
*this, EditSubAction::eRemoveTextProperty,
nsIEditor::eNext);
AutoSelectionRestorer selectionRestorer(selection, this);
AutoTransactionsConserveSelection dontChangeMySelection(this);
AutoTransactionsConserveSelection dontChangeMySelection(*this);
bool cancel, handled;
EditSubActionInfo subActionInfo(EditSubAction::eRemoveTextProperty);
@ -1405,7 +1405,7 @@ HTMLEditor::RelativeFontChange(FontSize aDir)
*this, EditSubAction::eSetTextProperty,
nsIEditor::eNext);
AutoSelectionRestorer selectionRestorer(selection, this);
AutoTransactionsConserveSelection dontChangeMySelection(this);
AutoTransactionsConserveSelection dontChangeMySelection(*this);
// Loop through the ranges in the selection
AutoRangeArray arrayOfRanges(selection);

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

@ -139,7 +139,7 @@ HTMLEditor::InsertCell(Element* aCell,
}
// Don't let Rules System change the selection.
AutoTransactionsConserveSelection dontChangeSelection(this);
AutoTransactionsConserveSelection dontChangeSelection(*this);
return InsertNodeWithTransaction(*newCell, pointToInsert);
}
@ -199,7 +199,7 @@ HTMLEditor::InsertTableCell(int32_t aNumber,
newCellIndex, ePreviousColumn,
false);
//...so suppress Rules System selection munging
AutoTransactionsConserveSelection dontChangeSelection(this);
AutoTransactionsConserveSelection dontChangeSelection(*this);
for (int32_t i = 0; i < aNumber; i++) {
RefPtr<Element> newCell;
@ -400,7 +400,7 @@ HTMLEditor::InsertTableColumn(int32_t aNumber,
startColIndex, ePreviousRow,
false);
//.. so suppress Rules System selection munging
AutoTransactionsConserveSelection dontChangeSelection(this);
AutoTransactionsConserveSelection dontChangeSelection(*this);
// If we are inserting after all existing columns
// Make sure table is "well formed"
@ -532,7 +532,7 @@ HTMLEditor::InsertTableRow(int32_t aNumber,
startColIndex, ePreviousColumn,
false);
//...so suppress Rules System selection munging
AutoTransactionsConserveSelection dontChangeSelection(this);
AutoTransactionsConserveSelection dontChangeSelection(*this);
RefPtr<Element> cellForRowParent;
int32_t cellsInRow = 0;
@ -749,7 +749,7 @@ HTMLEditor::DeleteTableCell(int32_t aNumber)
AutoSelectionSetterAfterTableEdit setCaret(*this, table, startRowIndex,
startColIndex, ePreviousColumn,
false);
AutoTransactionsConserveSelection dontChangeSelection(this);
AutoTransactionsConserveSelection dontChangeSelection(*this);
bool checkToDeleteRow = true;
bool checkToDeleteColumn = true;
@ -878,7 +878,7 @@ HTMLEditor::DeleteTableCell(int32_t aNumber)
AutoSelectionSetterAfterTableEdit setCaret(*this, table, startRowIndex,
startColIndex, ePreviousColumn,
false);
AutoTransactionsConserveSelection dontChangeSelection(this);
AutoTransactionsConserveSelection dontChangeSelection(*this);
rv = DeleteNodeWithTransaction(*cell);
// If we fail, don't try to delete any more cells???
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -913,7 +913,7 @@ HTMLEditor::DeleteTableCellContents()
*this, EditSubAction::eDeleteNode,
nsIEditor::eNext);
//Don't let Rules System change the selection
AutoTransactionsConserveSelection dontChangeSelection(this);
AutoTransactionsConserveSelection dontChangeSelection(*this);
RefPtr<Element> firstCell;
@ -1177,7 +1177,7 @@ HTMLEditor::DeleteTableRow(int32_t aNumber)
startColIndex, ePreviousRow,
false);
// Don't change selection during deletions
AutoTransactionsConserveSelection dontChangeSelection(this);
AutoTransactionsConserveSelection dontChangeSelection(*this);
if (firstCell && rangeCount > 1) {
// Use selected cells to determine what rows to delete
@ -1688,7 +1688,7 @@ HTMLEditor::SplitTableCell()
startColIndex, ePreviousColumn,
false);
//...so suppress Rules System selection munging
AutoTransactionsConserveSelection dontChangeSelection(this);
AutoTransactionsConserveSelection dontChangeSelection(*this);
RefPtr<Element> newCell;
int32_t rowIndex = startRowIndex;
@ -1973,7 +1973,7 @@ HTMLEditor::JoinTableCells(bool aMergeNonContiguousContents)
AutoPlaceholderBatch beginBatching(this);
//Don't let Rules System change the selection
AutoTransactionsConserveSelection dontChangeSelection(this);
AutoTransactionsConserveSelection dontChangeSelection(*this);
// Note: We dont' use AutoSelectionSetterAfterTableEdit here so the selection
// is retained after joining. This leaves the target cell selected

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

@ -113,21 +113,23 @@ InsertNodeTransaction::DoTransaction()
return error.StealNSResult();
}
// Only set selection to insertion point if editor gives permission
if (mEditorBase->GetShouldTxnSetSelection()) {
RefPtr<Selection> selection = mEditorBase->GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
// Place the selection just after the inserted element
EditorRawDOMPoint afterInsertedNode(mContentToInsert);
DebugOnly<bool> advanced = afterInsertedNode.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset after the inserted node");
selection->Collapse(afterInsertedNode, error);
if (NS_WARN_IF(error.Failed())) {
error.SuppressException();
}
if (!mEditorBase->AllowsTransactionsToChangeSelection()) {
return NS_OK;
}
RefPtr<Selection> selection = mEditorBase->GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
// Place the selection just after the inserted element.
EditorRawDOMPoint afterInsertedNode(mContentToInsert);
DebugOnly<bool> advanced = afterInsertedNode.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset after the inserted node");
selection->Collapse(afterInsertedNode, error);
if (NS_WARN_IF(error.Failed())) {
error.SuppressException();
}
return NS_OK;
}

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

@ -70,7 +70,7 @@ InsertTextTransaction::DoTransaction()
}
// Only set selection to insertion point if editor gives permission
if (mEditorBase->GetShouldTxnSetSelection()) {
if (mEditorBase->AllowsTransactionsToChangeSelection()) {
RefPtr<Selection> selection = mEditorBase->GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
@ -82,6 +82,8 @@ InsertTextTransaction::DoTransaction()
} else {
// Do nothing - DOM Range gravity will adjust selection
}
// XXX Other transactions do not do this but its callers do.
// Why do this transaction do this by itself?
mEditorBase->RangeUpdaterRef().
SelAdjInsertText(*mTextNode, mOffset, mStringToInsert);

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

@ -11,7 +11,6 @@
#include "nsDebug.h" // for NS_ASSERTION, etc.
#include "nsError.h" // for NS_ERROR_NULL_POINTER, etc.
#include "nsIContent.h" // for nsIContent
#include "nsIEditor.h" // for EditorBase::IsModifiableNode
#include "nsISupportsImpl.h" // for QueryInterface, etc.
namespace mozilla {
@ -60,7 +59,7 @@ JoinNodeTransaction::CanDoIt() const
!mLeftNode->GetParentNode()) {
return false;
}
return mEditorBase->IsModifiableNode(mLeftNode->GetParentNode());
return mEditorBase->IsModifiableNode(*mLeftNode->GetParentNode());
}
// After DoTransaction() and RedoTransaction(), the left node is removed from

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

@ -96,27 +96,32 @@ SplitNodeTransaction::DoTransaction()
// Insert the new node
mEditorBase->DoSplitNode(EditorDOMPoint(mStartOfRightNode),
*mNewLeftNode, error);
if (!mEditorBase->AllowsTransactionsToChangeSelection()) {
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
return NS_OK;
}
// XXX Really odd. The result of DoSplitNode() is respected only when
// we shouldn't set selection. Otherwise, it's overridden by the
// result of Selection.Collapse().
if (mEditorBase->GetShouldTxnSetSelection()) {
NS_WARNING_ASSERTION(!mEditorBase->Destroyed(),
"The editor has gone but SplitNodeTransaction keeps trying to modify "
"Selection");
RefPtr<Selection> selection = mEditorBase->GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
if (NS_WARN_IF(error.Failed())) {
// XXX This must be a bug.
error.SuppressException();
}
MOZ_ASSERT(mStartOfRightNode.Offset() == mNewLeftNode->Length());
EditorRawDOMPoint atEndOfLeftNode;
atEndOfLeftNode.SetToEndOf(mNewLeftNode);
selection->Collapse(atEndOfLeftNode, error);
NS_WARNING_ASSERTION(!mEditorBase->Destroyed(),
"The editor has gone but SplitNodeTransaction keeps trying to modify "
"Selection");
RefPtr<Selection> selection = mEditorBase->GetSelection();
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
if (NS_WARN_IF(error.Failed())) {
// XXX This must be a bug.
error.SuppressException();
}
MOZ_ASSERT(mStartOfRightNode.Offset() == mNewLeftNode->Length());
EditorRawDOMPoint atEndOfLeftNode;
atEndOfLeftNode.SetToEndOf(mNewLeftNode);
selection->Collapse(atEndOfLeftNode, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}

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

@ -378,7 +378,7 @@ TextEditRules::DidDoAction(Selection* aSelection,
// don't let any txns in here move the selection around behind our back.
// Note that this won't prevent explicit selection setting from working.
AutoTransactionsConserveSelection dontChangeMySelection(&TextEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(TextEditorRef());
switch (aInfo.mEditSubAction) {
case EditSubAction::eDeleteSelectedContent:
@ -849,7 +849,7 @@ TextEditRules::WillInsertText(EditSubAction aEditSubAction,
// aEditSubAction == EditSubAction::eInsertText
// don't change my selection in subtransactions
AutoTransactionsConserveSelection dontChangeMySelection(&TextEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(TextEditorRef());
EditorRawDOMPoint pointAfterStringInserted;
rv = TextEditorRef().InsertTextWithTransaction(*doc, *outString,
@ -1477,7 +1477,7 @@ TextEditRules::CreateTrailingBRIfNeeded()
}
if (!lastChild->IsHTMLElement(nsGkAtoms::br)) {
AutoTransactionsConserveSelection dontChangeMySelection(&TextEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(TextEditorRef());
EditorRawDOMPoint endOfRoot;
endOfRoot.SetToEndOf(rootElement);
CreateElementResult createMozBrResult = CreateMozBR(endOfRoot);
@ -1545,7 +1545,7 @@ TextEditRules::CreateBogusNodeIfNeeded()
}
// Skip adding the bogus node if body is read-only.
if (!TextEditorRef().IsModifiableNode(rootElement)) {
if (!TextEditorRef().IsModifiableNode(*rootElement)) {
return NS_OK;
}

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

@ -1095,7 +1095,7 @@ TextEditor::InsertParagraphSeparatorAsAction()
}
// don't change my selection in subtransactions
AutoTransactionsConserveSelection dontChangeMySelection(this);
AutoTransactionsConserveSelection dontChangeMySelection(*this);
// insert a linefeed character
EditorRawDOMPoint pointAfterInsertedLineBreak;

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

@ -115,7 +115,7 @@ TextEditor::InsertTextFromTransferable(nsITransferable* aTransferable)
&len)) &&
(bestFlavor.EqualsLiteral(kUnicodeMime) ||
bestFlavor.EqualsLiteral(kMozTextInternal))) {
AutoTransactionsConserveSelection dontChangeMySelection(this);
AutoTransactionsConserveSelection dontChangeMySelection(*this);
nsCOMPtr<nsISupportsString> textDataObj ( do_QueryInterface(genericDataObj) );
if (textDataObj && len > 0) {
nsAutoString stuffToPaste;

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

@ -1547,12 +1547,17 @@ WSRunObject::InsertNBSPAndRemoveFollowingASCIIWhitespaces(WSPoint aPoint)
return NS_ERROR_NULL_POINTER;
}
// First, insert an NBSP.
AutoTransactionsConserveSelection dontChangeMySelection(mHTMLEditor);
if (NS_WARN_IF(!mHTMLEditor)) {
return NS_ERROR_NOT_INITIALIZED;
}
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
// First, insert an NBSP.
AutoTransactionsConserveSelection dontChangeMySelection(*htmlEditor);
nsresult rv =
mHTMLEditor->InsertTextIntoTextNodeWithTransaction(
nsDependentSubstring(&kNBSP, 1),
*aPoint.mTextNode, aPoint.mOffset, true);
htmlEditor->InsertTextIntoTextNodeWithTransaction(
nsDependentSubstring(&kNBSP, 1),
*aPoint.mTextNode, aPoint.mOffset, true);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -1891,14 +1896,16 @@ WSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
}
if (leftCheck && rightCheck) {
// Now replace nbsp with space. First, insert a space
AutoTransactionsConserveSelection dontChangeMySelection(htmlEditor);
AutoTransactionsConserveSelection dontChangeMySelection(*htmlEditor);
nsAutoString spaceStr(char16_t(32));
nsresult rv =
htmlEditor->InsertTextIntoTextNodeWithTransaction(spaceStr,
*thePoint.mTextNode,
thePoint.mOffset,
true);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Finally, delete that nbsp
rv = DeleteRange(EditorRawDOMPoint(thePoint.mTextNode,
@ -1933,12 +1940,14 @@ WSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
}
// Finally, insert that nbsp before the ASCII ws run
AutoTransactionsConserveSelection dontChangeMySelection(htmlEditor);
AutoTransactionsConserveSelection dontChangeMySelection(*htmlEditor);
rv =
htmlEditor->InsertTextIntoTextNodeWithTransaction(
nsDependentSubstring(&kNBSP, 1),
*startNode, startOffset, true);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
}
return NS_OK;
@ -1985,13 +1994,18 @@ WSRunObject::ReplacePreviousNBSPIfUnncessary(
return NS_OK;
}
if (NS_WARN_IF(!mHTMLEditor)) {
return NS_ERROR_NOT_INITIALIZED;
}
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
// First, insert a space before the previous NBSP.
AutoTransactionsConserveSelection dontChangeMySelection(mHTMLEditor);
AutoTransactionsConserveSelection dontChangeMySelection(*htmlEditor);
nsAutoString spaceStr(char16_t(32));
nsresult rv =
mHTMLEditor->InsertTextIntoTextNodeWithTransaction(spaceStr,
*thePoint.mTextNode,
thePoint.mOffset, true);
htmlEditor->InsertTextIntoTextNodeWithTransaction(spaceStr,
*thePoint.mTextNode,
thePoint.mOffset, true);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -2034,15 +2048,22 @@ WSRunObject::CheckLeadingNBSP(WSFragment* aRun,
}
}
if (canConvert) {
if (NS_WARN_IF(!mHTMLEditor)) {
return NS_ERROR_NOT_INITIALIZED;
}
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
// First, insert a space
AutoTransactionsConserveSelection dontChangeMySelection(mHTMLEditor);
AutoTransactionsConserveSelection dontChangeMySelection(*htmlEditor);
nsAutoString spaceStr(char16_t(32));
nsresult rv =
mHTMLEditor->InsertTextIntoTextNodeWithTransaction(spaceStr,
*thePoint.mTextNode,
thePoint.mOffset,
true);
NS_ENSURE_SUCCESS(rv, rv);
htmlEditor->InsertTextIntoTextNodeWithTransaction(spaceStr,
*thePoint.mTextNode,
thePoint.mOffset,
true);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Finally, delete that nbsp
rv = DeleteRange(EditorRawDOMPoint(thePoint.mTextNode,

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

@ -216,16 +216,23 @@ interface nsIEditor : nsISupports
*/
void endTransaction();
boolean shouldTxnSetSelection();
/** Set the flag that prevents insertElementTxn from changing the selection
* @param should Set false to suppress changing the selection;
* i.e., before using InsertElement() to insert
* under <head> element
* WARNING: You must be very careful to reset back to PR_TRUE after
* setting PR_FALSE, else selection/caret is trashed
* for further editing.
*/
/**
* While setting the flag with this method to false, CreateElementTransaction,
* DeleteRangeTransaction, DeleteTextTransaction, InsertNodeTransaction,
* InsertTextTransaction and SplitNodeTransaction won't change Selection
* after modifying the DOM tree.
* Note that calling this with false does not guarantee that Selection won't
* be changed because other transaction may ignore this flag, editor itself
* may change selection, and current selection may become invalid after
* changing the DOM tree, etc.
* After calling this method with true, the caller should guarantee that
* Selection should be positioned where user expects.
*
* @param should false if you don't want above transactions to modify
* Selection automatically after modifying the DOM tree.
* Note that calling this with false does not guarantee
* that Selection is never changed.
*/
void setShouldTxnSetSelection(in boolean should);
/* ------------ Inline Spell Checking methods -------------- */

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

@ -1358,6 +1358,15 @@ ScrollFrameHelper::WantAsyncScroll() const
ScrollStyles styles = GetScrollStylesFromFrame();
nscoord oneDevPixel = GetScrolledFrame()->PresContext()->AppUnitsPerDevPixel();
nsRect scrollRange = GetScrollRange();
// If the page has a visual viewport size that's different from
// the layout viewport size at the current zoom level, we need to be
// able to scroll the visual viewport inside the layout viewport
// even if the page is not zoomable.
if (!GetScrollRangeForClamping().IsEqualInterior(scrollRange)) {
return true;
}
bool isVScrollable = (scrollRange.height >= oneDevPixel) &&
(styles.mVertical != NS_STYLE_OVERFLOW_HIDDEN);
bool isHScrollable = (scrollRange.width >= oneDevPixel) &&

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

@ -8558,6 +8558,7 @@ nsTextFrame::AddInlineMinISizeForFlow(gfxContext *aRenderingContext,
aData->mCurrentLine +=
textRun->GetMinAdvanceWidth(Range(start, flowEndInTextRun));
aData->mTrailingWhitespace = 0;
aData->mAtStartOfLine = false;
aData->OptionallyBreak();
return;
}

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

@ -3254,7 +3254,7 @@ pref("dom.ipc.processCount.privileged", 1);
pref("dom.ipc.keepProcessesAlive.privileged", 1);
// Whether a native event loop should be used in the content process.
#if defined(XP_WIN)
#if defined(XP_WIN) || defined(XP_MACOSX)
pref("dom.ipc.useNativeEventProcessing.content", false);
#else
pref("dom.ipc.useNativeEventProcessing.content", true);
@ -4989,7 +4989,11 @@ pref("extensions.webextensions.tabhide.enabled", true);
pref("extensions.webextensions.background-delayed-startup", false);
// Whether or not the installed extensions should be migrated to the storage.local IndexedDB backend.
#ifdef NIGHTLY_BUILD
pref("extensions.webextensions.ExtensionStorageIDB.enabled", true);
#else
pref("extensions.webextensions.ExtensionStorageIDB.enabled", false);
#endif
// if enabled, store execution times for API calls
pref("extensions.webextensions.enablePerformanceCounters", false);

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

@ -29,6 +29,13 @@ bench-ares6:
run:
mach: jsshell-bench --binary $JSSHELL --perfherder ares6
bench-asmjsapps:
description: asm.js Apps shell benchmark suite
treeherder:
symbol: js-bench(asm.js-apps)
run:
mach: jsshell-bench --binary $JSSHELL --perfherder asmjs-apps
bench-sixspeed:
description: Six-Speed JavaScript shell benchmark suite
treeherder:
@ -36,9 +43,9 @@ bench-sixspeed:
run:
mach: jsshell-bench --binary $JSSHELL --perfherder six-speed
bench-asmjsapps:
description: asm.js Apps shell benchmark suite
bench-sunspider:
description: SunSpider JavaScript shell benchmark suite
treeherder:
symbol: js-bench(asm.js-apps)
symbol: js-bench(sunspider)
run:
mach: jsshell-bench --binary $JSSHELL --perfherder asmjs-apps
mach: jsshell-bench --binary $JSSHELL --perfherder sunspider

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

@ -101,6 +101,19 @@ class Benchmark(object):
return proc.wait()
class RunOnceBenchmark(Benchmark):
def collect_results(self):
bench_total = 0
# NOTE: for this benchmark we run the test once, so we have a single value array
for bench, scores in self.scores.items():
for score, values in scores.items():
test_name = "{}-{}".format(self.name, score)
total = sum(values) / len(values)
self.suite['subtests'].append({'name': test_name, 'value': total})
bench_total += int(sum(values))
self.suite['value'] = bench_total
class Ares6(Benchmark):
name = 'ares6'
path = os.path.join('third_party', 'webkit', 'PerformanceTests', 'ARES-6')
@ -159,7 +172,51 @@ class Ares6(Benchmark):
self.suite['value'] = self.last_summary
class SixSpeed(Benchmark):
class AsmJSApps(RunOnceBenchmark):
name = 'asmjsapps'
path = os.path.join('third_party', 'webkit', 'PerformanceTests', 'asmjs-apps')
units = 'ms'
@property
def command(self):
if not self.args:
self.args = []
full_args = ['bash', 'harness.sh', self.shell + " " + " ".join(self.args)]
return full_args
def reset(self):
super(AsmJSApps, self).reset()
# Scores are of the form:
# {<bench_name>: {<score_name>: [<values>]}}
self.scores = defaultdict(lambda: defaultdict(list))
def process_results(self, output):
total = 0.0
tests = []
for line in output.splitlines():
m = re.search("(.+) - (\d+(\.\d+)?)", line)
if not m:
continue
name = m.group(1)
score = m.group(2)
total += float(score)
tests.append({ 'name': name, 'time': score })
tests.append({ 'name': '__total__', 'time': total })
return tests
def process_line(self, output):
m = re.search("(.+) - (\d+(\.\d+)?)", output)
if not m:
return
subtest = m.group(1)
score = m.group(2)
if subtest not in self.scores[self.name]:
self.scores[self.name][subtest] = []
self.scores[self.name][subtest].append(int(score))
class SixSpeed(RunOnceBenchmark):
name = 'six-speed'
path = os.path.join('third_party', 'webkit', 'PerformanceTests', 'six-speed')
units = 'ms'
@ -176,89 +233,50 @@ class SixSpeed(Benchmark):
# {<bench_name>: {<score_name>: [<values>]}}
self.scores = defaultdict(lambda: defaultdict(list))
def process_line(self, output):
m = re.search("(.+): (\d+)", output)
if not m:
return
subtest = m.group(1)
score = m.group(2)
if subtest not in self.scores[self.name]:
self.scores[self.name][subtest] = []
self.scores[self.name][subtest].append(int(score))
def process_line(self, output):
m = re.search("(.+): (\d+)", output)
if not m:
return
subtest = m.group(1)
score = m.group(2)
if subtest not in self.scores[self.name]:
self.scores[self.name][subtest] = []
self.scores[self.name][subtest].append(int(score))
def collect_results(self):
bench_total = 0
# NOTE: for this benchmark we run the test once, so we have a single value array
for bench, scores in self.scores.items():
for score, values in scores.items():
test_name = "{}-{}".format(self.name, score)
total = sum(values) / len(values)
self.suite['subtests'].append({'name': test_name, 'value': total})
bench_total += int(sum(values))
self.suite['value'] = bench_total
class AsmJSApps(Benchmark):
name = 'asmjsapps'
path = os.path.join('third_party', 'webkit', 'PerformanceTests', 'asmjs-apps')
class SunSpider(RunOnceBenchmark):
name = 'sunspider'
path = os.path.join('third_party', 'webkit', 'PerformanceTests', 'SunSpider', 'sunspider-0.9.1')
units = 'ms'
@property
def command(self):
if not self.args:
self.args = []
full_args = ['bash', 'harness.sh', self.shell + " " + " ".join(self.args)]
return full_args
cmd = super(SunSpider, self).command
return cmd + ['sunspider-standalone-driver.js']
def reset(self):
super(AsmJSApps, self).reset()
super(SunSpider, self).reset()
# Scores are of the form:
# {<bench_name>: {<score_name>: [<values>]}}
self.scores = defaultdict(lambda: defaultdict(list))
def process_results(self, output):
total = 0.0
tests = []
for line in output.splitlines():
m = re.search("(.+) - (\d+(\.\d+)?)", line)
if not m:
continue
name = m.group(1)
score = m.group(2)
total += float(score)
tests.append({ 'name': name, 'time': score })
tests.append({ 'name': '__total__', 'time': total })
return tests
def process_line(self, output):
m = re.search("(.+) - (\d+(\.\d+)?)", output)
if not m:
return
subtest = m.group(1)
score = m.group(2)
if subtest not in self.scores[self.name]:
self.scores[self.name][subtest] = []
self.scores[self.name][subtest].append(int(score))
def collect_results(self):
bench_total = 0
# NOTE: for this benchmark we run the test once, so we have a single value array
for bench, scores in self.scores.items():
for score, values in scores.items():
test_name = "{}-{}".format(self.name, score)
total = sum(values) / len(values)
self.suite['subtests'].append({'name': test_name, 'value': total})
bench_total += int(sum(values))
self.suite['value'] = bench_total
def process_line(self, output):
m = re.search("(.+): (\d+)", output)
if not m:
return
subtest = m.group(1)
score = m.group(2)
if subtest not in self.scores[self.name]:
self.scores[self.name][subtest] = []
self.scores[self.name][subtest].append(int(score))
all_benchmarks = {
'asmjs-apps': AsmJSApps,
'ares6': Ares6,
'six-speed': SixSpeed,
'asmjs-apps': AsmJSApps,
'sunspider': SunSpider
}

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

@ -1,4 +1,6 @@
[DEFAULT]
[browser_baselinecoverage.js]
run-if = ccov && verify
[browser_baselinecoverage_browser-chrome.js]
run-if = ccov && verify

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

@ -0,0 +1,22 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-disable mozilla/no-arbitrary-setTimeout */
"use strict";
const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm", {});
add_task(async function() {
requestLongerTimeout(2);
let newWin = await BrowserTestUtils.openNewBrowserWindow();
await BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank"
}, async function(browser) {
ok(true, "Collecting baseline coverage for browser-chrome tests.");
await new Promise((c) => setTimeout(c, 30 * 1000));
});
await BrowserTestUtils.closeWindow(newWin);
});

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

@ -193,7 +193,7 @@ class CodeCoverageMixin(SingleTestMixin):
# TODO: Add tests that haven't been run for a while (a week? N pushes?)
# Add baseline code coverage collection tests
baseline_tests = {
baseline_tests_by_ext = {
'.html': {
'test': 'testing/mochitest/baselinecoverage/plain/test_baselinecoverage.html',
'suite': 'plain'
@ -208,6 +208,11 @@ class CodeCoverageMixin(SingleTestMixin):
}
}
baseline_tests_by_suite = {
'browser-chrome': 'testing/mochitest/baselinecoverage/browser_chrome/'
'browser_baselinecoverage_browser-chrome.js'
}
wpt_baseline_test = 'tests/web-platform/mozilla/tests/baselinecoverage/wpt_baselinecoverage.html' # NOQA: E501
if self.config.get('per_test_category') == "web-platform":
if 'testharness' not in self.suites:
@ -220,15 +225,24 @@ class CodeCoverageMixin(SingleTestMixin):
# the baseline tests that are needed.
tests_to_add = {}
for suite in self.suites:
if len(self.suites[suite]) == 0:
continue
if suite in baseline_tests_by_suite:
if suite not in tests_to_add:
tests_to_add[suite] = []
tests_to_add[suite].append(baseline_tests_by_suite[suite])
continue
# Default to file types if the suite has no baseline
for test in self.suites[suite]:
_, test_ext = os.path.splitext(test)
if test_ext not in baseline_tests:
if test_ext not in baseline_tests_by_ext:
# Add the '.js' test as a default baseline
# if none other exists.
test_ext = '.js'
baseline_test_suite = baseline_tests[test_ext]['suite']
baseline_test_name = baseline_tests[test_ext]['test']
baseline_test_suite = baseline_tests_by_ext[test_ext]['suite']
baseline_test_name = baseline_tests_by_ext[test_ext]['test']
if baseline_test_suite not in tests_to_add:
tests_to_add[baseline_test_suite] = []
@ -401,7 +415,8 @@ class CodeCoverageMixin(SingleTestMixin):
return
# Get the baseline tests that were run.
baseline_tests_cov = {}
baseline_tests_ext_cov = {}
baseline_tests_suite_cov = {}
for suite, data in self.per_test_reports.items():
for test, grcov_file in data.items():
if 'baselinecoverage' not in test:
@ -410,9 +425,14 @@ class CodeCoverageMixin(SingleTestMixin):
# TODO: Optimize this part which loads JSONs
# with a size of about 40Mb into memory for diffing later.
# Bug 1460064 is filed for this.
_, baseline_filetype = os.path.splitext(test)
with open(grcov_file, 'r') as f:
baseline_tests_cov[baseline_filetype] = json.load(f)
data = json.load(f)
if suite in test:
baseline_tests_suite_cov[suite] = data
else:
_, baseline_filetype = os.path.splitext(test)
baseline_tests_ext_cov[baseline_filetype] = data
dest = os.path.join(dirs['abs_blob_upload_dir'], 'per-test-coverage-reports.zip')
with zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED) as z:
@ -433,19 +453,21 @@ class CodeCoverageMixin(SingleTestMixin):
# Get baseline coverage
baseline_coverage = {}
if self.config.get('per_test_category') == "web-platform":
baseline_coverage = baseline_tests_cov['.html']
if suite in baseline_tests_suite_cov:
baseline_coverage = baseline_tests_suite_cov[suite]
elif self.config.get('per_test_category') == "web-platform":
baseline_coverage = baseline_tests_ext_cov['.html']
else:
for file_type in baseline_tests_cov:
for file_type in baseline_tests_ext_cov:
if not test.endswith(file_type):
continue
baseline_coverage = baseline_tests_cov[file_type]
baseline_coverage = baseline_tests_ext_cov[file_type]
break
if not baseline_coverage:
# Default to the '.js' baseline as it is the largest
self.info("Did not find a baseline test for: " + test)
baseline_coverage = baseline_tests_cov['.js']
baseline_coverage = baseline_tests_ext_cov['.js']
unique_coverage = rm_baseline_cov(baseline_coverage, report)

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

@ -135433,6 +135433,18 @@
{}
]
],
"css/css-text/overflow-wrap/overflow-wrap-min-content-size-003.html": [
[
"/css/css-text/overflow-wrap/overflow-wrap-min-content-size-003.html",
[
[
"/css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-003-ref.html",
"=="
]
],
{}
]
],
"css/css-text/overflow-wrap/word-wrap-001.html": [
[
"/css/css-text/overflow-wrap/word-wrap-001.html",
@ -258273,6 +258285,11 @@
{}
]
],
"css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-003-ref.html": [
[
{}
]
],
"css/css-text/support/1x1-green.png": [
[
{}
@ -543200,6 +543217,10 @@
"5b3b1f19d7ae6374224da75567b3ba5279d16127",
"reftest"
],
"css/css-text/overflow-wrap/overflow-wrap-min-content-size-003.html": [
"d1af28ffad4161c1dba7567cacb3b06098b155fa",
"reftest"
],
"css/css-text/overflow-wrap/reference/overflow-wrap-break-word-001-ref.html": [
"0e0300a72dc920a5ffb54cda6fbe84a2f517d010",
"support"
@ -543224,6 +543245,10 @@
"055ffbf3ca1377aaa502ffa02c52c8e49604a286",
"support"
],
"css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-003-ref.html": [
"a71b3a34d6920a5404cf7c954fa1c8ab66b788b4",
"support"
],
"css/css-text/overflow-wrap/word-wrap-001.html": [
"dd5f0f2bf132de85c7a1045e88aa3ad2b72616c1",
"reftest"

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

@ -0,0 +1,33 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Text Test: overflow-wrap: break-word and intrinsic sizing</title>
<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org/">
<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-text-3/#overflow-wrap-property">
<meta name="flags" content="ahem">
<link rel="match" href="reference/overflow-wrap-min-content-size-003-ref.html">
<meta name="assert" content="overflow-wrap:break-word breaks at edge of inline elements.">
<style>
#wrapper {
width: 0px;
font: 16px / 1 Ahem;
overflow-wrap: break-word;
color: green;
}
#test {
float: left;
}
#reference {
position: absolute;
width: 16px;
height: 128px;
background: red;
z-index: -1;
}
</style>
<p>Test passes if there is a vertical green bar below.
<div id="wrapper">
<div id="reference"></div>
<div id="test"><span>X</span><span>X</span><span>X</span><span>X</span><span>X</span><span>X</span><span>X</span><span>X</span></div>
</div>

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

@ -0,0 +1,29 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Text Test reference</title>
<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org/">
<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
<meta name="flags" content="ahem">
<style>
#wrapper {
width: 0px;
font: 16px / 1 Ahem;
color: green;
}
#test {
float: left;
}
#reference {
position: absolute;
width: 16px;
height: 128px;
background: red;
z-index: -1;
}
</style>
<p>Test passes if there is a vertical green bar below.
<div id="wrapper">
<div id="reference"></div>
<div id="test">X<br>X<br>X<br>X<br>X<br>X<br>X<br>X</div>
</div>

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

@ -0,0 +1,337 @@
// 3D Cube Rotation
// http://www.speich.net/computer/moztesting/3d.htm
// Created by Simon Speich
var Q = new Array();
var MTrans = new Array(); // transformation matrix
var MQube = new Array(); // position information of qube
var I = new Array(); // entity matrix
var Origin = new Object();
var Testing = new Object();
var LoopTimer;
var DisplArea = new Object();
DisplArea.Width = 300;
DisplArea.Height = 300;
function DrawLine(From, To) {
var x1 = From.V[0];
var x2 = To.V[0];
var y1 = From.V[1];
var y2 = To.V[1];
var dx = Math.abs(x2 - x1);
var dy = Math.abs(y2 - y1);
var x = x1;
var y = y1;
var IncX1, IncY1;
var IncX2, IncY2;
var Den;
var Num;
var NumAdd;
var NumPix;
if (x2 >= x1) { IncX1 = 1; IncX2 = 1; }
else { IncX1 = -1; IncX2 = -1; }
if (y2 >= y1) { IncY1 = 1; IncY2 = 1; }
else { IncY1 = -1; IncY2 = -1; }
if (dx >= dy) {
IncX1 = 0;
IncY2 = 0;
Den = dx;
Num = dx / 2;
NumAdd = dy;
NumPix = dx;
}
else {
IncX2 = 0;
IncY1 = 0;
Den = dy;
Num = dy / 2;
NumAdd = dx;
NumPix = dy;
}
NumPix = Math.round(Q.LastPx + NumPix);
var i = Q.LastPx;
for (; i < NumPix; i++) {
Num += NumAdd;
if (Num >= Den) {
Num -= Den;
x += IncX1;
y += IncY1;
}
x += IncX2;
y += IncY2;
}
Q.LastPx = NumPix;
}
function CalcCross(V0, V1) {
var Cross = new Array();
Cross[0] = V0[1]*V1[2] - V0[2]*V1[1];
Cross[1] = V0[2]*V1[0] - V0[0]*V1[2];
Cross[2] = V0[0]*V1[1] - V0[1]*V1[0];
return Cross;
}
function CalcNormal(V0, V1, V2) {
var A = new Array(); var B = new Array();
for (var i = 0; i < 3; i++) {
A[i] = V0[i] - V1[i];
B[i] = V2[i] - V1[i];
}
A = CalcCross(A, B);
var Length = Math.sqrt(A[0]*A[0] + A[1]*A[1] + A[2]*A[2]);
for (var i = 0; i < 3; i++) A[i] = A[i] / Length;
A[3] = 1;
return A;
}
function CreateP(X,Y,Z) {
this.V = [X,Y,Z,1];
}
// multiplies two matrices
function MMulti(M1, M2) {
var M = [[],[],[],[]];
var i = 0;
var j = 0;
for (; i < 4; i++) {
j = 0;
for (; j < 4; j++) M[i][j] = M1[i][0] * M2[0][j] + M1[i][1] * M2[1][j] + M1[i][2] * M2[2][j] + M1[i][3] * M2[3][j];
}
return M;
}
//multiplies matrix with vector
function VMulti(M, V) {
var Vect = new Array();
var i = 0;
for (;i < 4; i++) Vect[i] = M[i][0] * V[0] + M[i][1] * V[1] + M[i][2] * V[2] + M[i][3] * V[3];
return Vect;
}
function VMulti2(M, V) {
var Vect = new Array();
var i = 0;
for (;i < 3; i++) Vect[i] = M[i][0] * V[0] + M[i][1] * V[1] + M[i][2] * V[2];
return Vect;
}
// add to matrices
function MAdd(M1, M2) {
var M = [[],[],[],[]];
var i = 0;
var j = 0;
for (; i < 4; i++) {
j = 0;
for (; j < 4; j++) M[i][j] = M1[i][j] + M2[i][j];
}
return M;
}
function Translate(M, Dx, Dy, Dz) {
var T = [
[1,0,0,Dx],
[0,1,0,Dy],
[0,0,1,Dz],
[0,0,0,1]
];
return MMulti(T, M);
}
function RotateX(M, Phi) {
var a = Phi;
a *= Math.PI / 180;
var Cos = Math.cos(a);
var Sin = Math.sin(a);
var R = [
[1,0,0,0],
[0,Cos,-Sin,0],
[0,Sin,Cos,0],
[0,0,0,1]
];
return MMulti(R, M);
}
function RotateY(M, Phi) {
var a = Phi;
a *= Math.PI / 180;
var Cos = Math.cos(a);
var Sin = Math.sin(a);
var R = [
[Cos,0,Sin,0],
[0,1,0,0],
[-Sin,0,Cos,0],
[0,0,0,1]
];
return MMulti(R, M);
}
function RotateZ(M, Phi) {
var a = Phi;
a *= Math.PI / 180;
var Cos = Math.cos(a);
var Sin = Math.sin(a);
var R = [
[Cos,-Sin,0,0],
[Sin,Cos,0,0],
[0,0,1,0],
[0,0,0,1]
];
return MMulti(R, M);
}
function DrawQube() {
// calc current normals
var CurN = new Array();
var i = 5;
Q.LastPx = 0;
for (; i > -1; i--) CurN[i] = VMulti2(MQube, Q.Normal[i]);
if (CurN[0][2] < 0) {
if (!Q.Line[0]) { DrawLine(Q[0], Q[1]); Q.Line[0] = true; };
if (!Q.Line[1]) { DrawLine(Q[1], Q[2]); Q.Line[1] = true; };
if (!Q.Line[2]) { DrawLine(Q[2], Q[3]); Q.Line[2] = true; };
if (!Q.Line[3]) { DrawLine(Q[3], Q[0]); Q.Line[3] = true; };
}
if (CurN[1][2] < 0) {
if (!Q.Line[2]) { DrawLine(Q[3], Q[2]); Q.Line[2] = true; };
if (!Q.Line[9]) { DrawLine(Q[2], Q[6]); Q.Line[9] = true; };
if (!Q.Line[6]) { DrawLine(Q[6], Q[7]); Q.Line[6] = true; };
if (!Q.Line[10]) { DrawLine(Q[7], Q[3]); Q.Line[10] = true; };
}
if (CurN[2][2] < 0) {
if (!Q.Line[4]) { DrawLine(Q[4], Q[5]); Q.Line[4] = true; };
if (!Q.Line[5]) { DrawLine(Q[5], Q[6]); Q.Line[5] = true; };
if (!Q.Line[6]) { DrawLine(Q[6], Q[7]); Q.Line[6] = true; };
if (!Q.Line[7]) { DrawLine(Q[7], Q[4]); Q.Line[7] = true; };
}
if (CurN[3][2] < 0) {
if (!Q.Line[4]) { DrawLine(Q[4], Q[5]); Q.Line[4] = true; };
if (!Q.Line[8]) { DrawLine(Q[5], Q[1]); Q.Line[8] = true; };
if (!Q.Line[0]) { DrawLine(Q[1], Q[0]); Q.Line[0] = true; };
if (!Q.Line[11]) { DrawLine(Q[0], Q[4]); Q.Line[11] = true; };
}
if (CurN[4][2] < 0) {
if (!Q.Line[11]) { DrawLine(Q[4], Q[0]); Q.Line[11] = true; };
if (!Q.Line[3]) { DrawLine(Q[0], Q[3]); Q.Line[3] = true; };
if (!Q.Line[10]) { DrawLine(Q[3], Q[7]); Q.Line[10] = true; };
if (!Q.Line[7]) { DrawLine(Q[7], Q[4]); Q.Line[7] = true; };
}
if (CurN[5][2] < 0) {
if (!Q.Line[8]) { DrawLine(Q[1], Q[5]); Q.Line[8] = true; };
if (!Q.Line[5]) { DrawLine(Q[5], Q[6]); Q.Line[5] = true; };
if (!Q.Line[9]) { DrawLine(Q[6], Q[2]); Q.Line[9] = true; };
if (!Q.Line[1]) { DrawLine(Q[2], Q[1]); Q.Line[1] = true; };
}
Q.Line = [false,false,false,false,false,false,false,false,false,false,false,false];
Q.LastPx = 0;
}
function Loop() {
if (Testing.LoopCount > Testing.LoopMax) return;
var TestingStr = String(Testing.LoopCount);
while (TestingStr.length < 3) TestingStr = "0" + TestingStr;
MTrans = Translate(I, -Q[8].V[0], -Q[8].V[1], -Q[8].V[2]);
MTrans = RotateX(MTrans, 1);
MTrans = RotateY(MTrans, 3);
MTrans = RotateZ(MTrans, 5);
MTrans = Translate(MTrans, Q[8].V[0], Q[8].V[1], Q[8].V[2]);
MQube = MMulti(MTrans, MQube);
var i = 8;
for (; i > -1; i--) {
Q[i].V = VMulti(MTrans, Q[i].V);
}
DrawQube();
Testing.LoopCount++;
Loop();
}
function Init(CubeSize) {
// init/reset vars
Origin.V = [150,150,20,1];
Testing.LoopCount = 0;
Testing.LoopMax = 50;
Testing.TimeMax = 0;
Testing.TimeAvg = 0;
Testing.TimeMin = 0;
Testing.TimeTemp = 0;
Testing.TimeTotal = 0;
Testing.Init = false;
// transformation matrix
MTrans = [
[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,1]
];
// position information of qube
MQube = [
[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,1]
];
// entity matrix
I = [
[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,1]
];
// create qube
Q[0] = new CreateP(-CubeSize,-CubeSize, CubeSize);
Q[1] = new CreateP(-CubeSize, CubeSize, CubeSize);
Q[2] = new CreateP( CubeSize, CubeSize, CubeSize);
Q[3] = new CreateP( CubeSize,-CubeSize, CubeSize);
Q[4] = new CreateP(-CubeSize,-CubeSize,-CubeSize);
Q[5] = new CreateP(-CubeSize, CubeSize,-CubeSize);
Q[6] = new CreateP( CubeSize, CubeSize,-CubeSize);
Q[7] = new CreateP( CubeSize,-CubeSize,-CubeSize);
// center of gravity
Q[8] = new CreateP(0, 0, 0);
// anti-clockwise edge check
Q.Edge = [[0,1,2],[3,2,6],[7,6,5],[4,5,1],[4,0,3],[1,5,6]];
// calculate squad normals
Q.Normal = new Array();
for (var i = 0; i < Q.Edge.length; i++) Q.Normal[i] = CalcNormal(Q[Q.Edge[i][0]].V, Q[Q.Edge[i][1]].V, Q[Q.Edge[i][2]].V);
// line drawn ?
Q.Line = [false,false,false,false,false,false,false,false,false,false,false,false];
// create line pixels
Q.NumPx = 9 * 2 * CubeSize;
for (var i = 0; i < Q.NumPx; i++) CreateP(0,0,0);
MTrans = Translate(MTrans, Origin.V[0], Origin.V[1], Origin.V[2]);
MQube = MMulti(MTrans, MQube);
var i = 0;
for (; i < 9; i++) {
Q[i].V = VMulti(MTrans, Q[i].V);
}
DrawQube();
Testing.Init = true;
Loop();
}
for ( var i = 20; i <= 160; i *= 2 ) {
Init(i);
}
Q = null;
MTrans = null;
MQube = null;
I = null;
Origin = null;
Testing = null;
LoopTime = null;
DisplArea = null;

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

@ -0,0 +1,54 @@
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
var loops = 15
var nx = 120
var nz = 120
function morph(a, f) {
var PI2nx = Math.PI * 8/nx
var sin = Math.sin
var f30 = -(50 * sin(f*Math.PI*2))
for (var i = 0; i < nz; ++i) {
for (var j = 0; j < nx; ++j) {
a[3*(i*nx+j)+1] = sin((j-1) * PI2nx ) * -f30
}
}
}
var a = Array()
for (var i=0; i < nx*nz*3; ++i)
a[i] = 0
for (var i = 0; i < loops; ++i) {
morph(a, i/loops)
}
testOutput = 0;
for (var i = 0; i < nx; i++)
testOutput += a[3*(i*nx+i)+1];
a = null;

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

@ -0,0 +1,441 @@
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
function createVector(x,y,z) {
return new Array(x,y,z);
}
function sqrLengthVector(self) {
return self[0] * self[0] + self[1] * self[1] + self[2] * self[2];
}
function lengthVector(self) {
return Math.sqrt(self[0] * self[0] + self[1] * self[1] + self[2] * self[2]);
}
function addVector(self, v) {
self[0] += v[0];
self[1] += v[1];
self[2] += v[2];
return self;
}
function subVector(self, v) {
self[0] -= v[0];
self[1] -= v[1];
self[2] -= v[2];
return self;
}
function scaleVector(self, scale) {
self[0] *= scale;
self[1] *= scale;
self[2] *= scale;
return self;
}
function normaliseVector(self) {
var len = Math.sqrt(self[0] * self[0] + self[1] * self[1] + self[2] * self[2]);
self[0] /= len;
self[1] /= len;
self[2] /= len;
return self;
}
function add(v1, v2) {
return new Array(v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]);
}
function sub(v1, v2) {
return new Array(v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]);
}
function scalev(v1, v2) {
return new Array(v1[0] * v2[0], v1[1] * v2[1], v1[2] * v2[2]);
}
function dot(v1, v2) {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}
function scale(v, scale) {
return [v[0] * scale, v[1] * scale, v[2] * scale];
}
function cross(v1, v2) {
return [v1[1] * v2[2] - v1[2] * v2[1],
v1[2] * v2[0] - v1[0] * v2[2],
v1[0] * v2[1] - v1[1] * v2[0]];
}
function normalise(v) {
var len = lengthVector(v);
return [v[0] / len, v[1] / len, v[2] / len];
}
function transformMatrix(self, v) {
var vals = self;
var x = vals[0] * v[0] + vals[1] * v[1] + vals[2] * v[2] + vals[3];
var y = vals[4] * v[0] + vals[5] * v[1] + vals[6] * v[2] + vals[7];
var z = vals[8] * v[0] + vals[9] * v[1] + vals[10] * v[2] + vals[11];
return [x, y, z];
}
function invertMatrix(self) {
var temp = new Array(16);
var tx = -self[3];
var ty = -self[7];
var tz = -self[11];
for (h = 0; h < 3; h++)
for (v = 0; v < 3; v++)
temp[h + v * 4] = self[v + h * 4];
for (i = 0; i < 11; i++)
self[i] = temp[i];
self[3] = tx * self[0] + ty * self[1] + tz * self[2];
self[7] = tx * self[4] + ty * self[5] + tz * self[6];
self[11] = tx * self[8] + ty * self[9] + tz * self[10];
return self;
}
// Triangle intersection using barycentric coord method
function Triangle(p1, p2, p3) {
var edge1 = sub(p3, p1);
var edge2 = sub(p2, p1);
var normal = cross(edge1, edge2);
if (Math.abs(normal[0]) > Math.abs(normal[1]))
if (Math.abs(normal[0]) > Math.abs(normal[2]))
this.axis = 0;
else
this.axis = 2;
else
if (Math.abs(normal[1]) > Math.abs(normal[2]))
this.axis = 1;
else
this.axis = 2;
var u = (this.axis + 1) % 3;
var v = (this.axis + 2) % 3;
var u1 = edge1[u];
var v1 = edge1[v];
var u2 = edge2[u];
var v2 = edge2[v];
this.normal = normalise(normal);
this.nu = normal[u] / normal[this.axis];
this.nv = normal[v] / normal[this.axis];
this.nd = dot(normal, p1) / normal[this.axis];
var det = u1 * v2 - v1 * u2;
this.eu = p1[u];
this.ev = p1[v];
this.nu1 = u1 / det;
this.nv1 = -v1 / det;
this.nu2 = v2 / det;
this.nv2 = -u2 / det;
this.material = [0.7, 0.7, 0.7];
}
Triangle.prototype.intersect = function(orig, dir, near, far) {
var u = (this.axis + 1) % 3;
var v = (this.axis + 2) % 3;
var d = dir[this.axis] + this.nu * dir[u] + this.nv * dir[v];
var t = (this.nd - orig[this.axis] - this.nu * orig[u] - this.nv * orig[v]) / d;
if (t < near || t > far)
return null;
var Pu = orig[u] + t * dir[u] - this.eu;
var Pv = orig[v] + t * dir[v] - this.ev;
var a2 = Pv * this.nu1 + Pu * this.nv1;
if (a2 < 0)
return null;
var a3 = Pu * this.nu2 + Pv * this.nv2;
if (a3 < 0)
return null;
if ((a2 + a3) > 1)
return null;
return t;
}
function Scene(a_triangles) {
this.triangles = a_triangles;
this.lights = [];
this.ambient = [0,0,0];
this.background = [0.8,0.8,1];
}
var zero = new Array(0,0,0);
Scene.prototype.intersect = function(origin, dir, near, far) {
var closest = null;
for (i = 0; i < this.triangles.length; i++) {
var triangle = this.triangles[i];
var d = triangle.intersect(origin, dir, near, far);
if (d == null || d > far || d < near)
continue;
far = d;
closest = triangle;
}
if (!closest)
return [this.background[0],this.background[1],this.background[2]];
var normal = closest.normal;
var hit = add(origin, scale(dir, far));
if (dot(dir, normal) > 0)
normal = [-normal[0], -normal[1], -normal[2]];
var colour = null;
if (closest.shader) {
colour = closest.shader(closest, hit, dir);
} else {
colour = closest.material;
}
// do reflection
var reflected = null;
if (colour.reflection > 0.001) {
var reflection = addVector(scale(normal, -2*dot(dir, normal)), dir);
reflected = this.intersect(hit, reflection, 0.0001, 1000000);
if (colour.reflection >= 0.999999)
return reflected;
}
var l = [this.ambient[0], this.ambient[1], this.ambient[2]];
for (var i = 0; i < this.lights.length; i++) {
var light = this.lights[i];
var toLight = sub(light, hit);
var distance = lengthVector(toLight);
scaleVector(toLight, 1.0/distance);
distance -= 0.0001;
if (this.blocked(hit, toLight, distance))
continue;
var nl = dot(normal, toLight);
if (nl > 0)
addVector(l, scale(light.colour, nl));
}
l = scalev(l, colour);
if (reflected) {
l = addVector(scaleVector(l, 1 - colour.reflection), scaleVector(reflected, colour.reflection));
}
return l;
}
Scene.prototype.blocked = function(O, D, far) {
var near = 0.0001;
var closest = null;
for (i = 0; i < this.triangles.length; i++) {
var triangle = this.triangles[i];
var d = triangle.intersect(O, D, near, far);
if (d == null || d > far || d < near)
continue;
return true;
}
return false;
}
// this camera code is from notes i made ages ago, it is from *somewhere* -- i cannot remember where
// that somewhere is
function Camera(origin, lookat, up) {
var zaxis = normaliseVector(subVector(lookat, origin));
var xaxis = normaliseVector(cross(up, zaxis));
var yaxis = normaliseVector(cross(xaxis, subVector([0,0,0], zaxis)));
var m = new Array(16);
m[0] = xaxis[0]; m[1] = xaxis[1]; m[2] = xaxis[2];
m[4] = yaxis[0]; m[5] = yaxis[1]; m[6] = yaxis[2];
m[8] = zaxis[0]; m[9] = zaxis[1]; m[10] = zaxis[2];
invertMatrix(m);
m[3] = 0; m[7] = 0; m[11] = 0;
this.origin = origin;
this.directions = new Array(4);
this.directions[0] = normalise([-0.7, 0.7, 1]);
this.directions[1] = normalise([ 0.7, 0.7, 1]);
this.directions[2] = normalise([ 0.7, -0.7, 1]);
this.directions[3] = normalise([-0.7, -0.7, 1]);
this.directions[0] = transformMatrix(m, this.directions[0]);
this.directions[1] = transformMatrix(m, this.directions[1]);
this.directions[2] = transformMatrix(m, this.directions[2]);
this.directions[3] = transformMatrix(m, this.directions[3]);
}
Camera.prototype.generateRayPair = function(y) {
rays = new Array(new Object(), new Object());
rays[0].origin = this.origin;
rays[1].origin = this.origin;
rays[0].dir = addVector(scale(this.directions[0], y), scale(this.directions[3], 1 - y));
rays[1].dir = addVector(scale(this.directions[1], y), scale(this.directions[2], 1 - y));
return rays;
}
function renderRows(camera, scene, pixels, width, height, starty, stopy) {
for (var y = starty; y < stopy; y++) {
var rays = camera.generateRayPair(y / height);
for (var x = 0; x < width; x++) {
var xp = x / width;
var origin = addVector(scale(rays[0].origin, xp), scale(rays[1].origin, 1 - xp));
var dir = normaliseVector(addVector(scale(rays[0].dir, xp), scale(rays[1].dir, 1 - xp)));
var l = scene.intersect(origin, dir);
pixels[y][x] = l;
}
}
}
Camera.prototype.render = function(scene, pixels, width, height) {
var cam = this;
var row = 0;
renderRows(cam, scene, pixels, width, height, 0, height);
}
function raytraceScene()
{
var startDate = new Date().getTime();
var numTriangles = 2 * 6;
var triangles = new Array();//numTriangles);
var tfl = createVector(-10, 10, -10);
var tfr = createVector( 10, 10, -10);
var tbl = createVector(-10, 10, 10);
var tbr = createVector( 10, 10, 10);
var bfl = createVector(-10, -10, -10);
var bfr = createVector( 10, -10, -10);
var bbl = createVector(-10, -10, 10);
var bbr = createVector( 10, -10, 10);
// cube!!!
// front
var i = 0;
triangles[i++] = new Triangle(tfl, tfr, bfr);
triangles[i++] = new Triangle(tfl, bfr, bfl);
// back
triangles[i++] = new Triangle(tbl, tbr, bbr);
triangles[i++] = new Triangle(tbl, bbr, bbl);
// triangles[i-1].material = [0.7,0.2,0.2];
// triangles[i-1].material.reflection = 0.8;
// left
triangles[i++] = new Triangle(tbl, tfl, bbl);
// triangles[i-1].reflection = 0.6;
triangles[i++] = new Triangle(tfl, bfl, bbl);
// triangles[i-1].reflection = 0.6;
// right
triangles[i++] = new Triangle(tbr, tfr, bbr);
triangles[i++] = new Triangle(tfr, bfr, bbr);
// top
triangles[i++] = new Triangle(tbl, tbr, tfr);
triangles[i++] = new Triangle(tbl, tfr, tfl);
// bottom
triangles[i++] = new Triangle(bbl, bbr, bfr);
triangles[i++] = new Triangle(bbl, bfr, bfl);
//Floor!!!!
var green = createVector(0.0, 0.4, 0.0);
var grey = createVector(0.4, 0.4, 0.4);
grey.reflection = 1.0;
var floorShader = function(tri, pos, view) {
var x = ((pos[0]/32) % 2 + 2) % 2;
var z = ((pos[2]/32 + 0.3) % 2 + 2) % 2;
if (x < 1 != z < 1) {
//in the real world we use the fresnel term...
// var angle = 1-dot(view, tri.normal);
// angle *= angle;
// angle *= angle;
// angle *= angle;
//grey.reflection = angle;
return grey;
} else
return green;
}
var ffl = createVector(-1000, -30, -1000);
var ffr = createVector( 1000, -30, -1000);
var fbl = createVector(-1000, -30, 1000);
var fbr = createVector( 1000, -30, 1000);
triangles[i++] = new Triangle(fbl, fbr, ffr);
triangles[i-1].shader = floorShader;
triangles[i++] = new Triangle(fbl, ffr, ffl);
triangles[i-1].shader = floorShader;
var _scene = new Scene(triangles);
_scene.lights[0] = createVector(20, 38, -22);
_scene.lights[0].colour = createVector(0.7, 0.3, 0.3);
_scene.lights[1] = createVector(-23, 40, 17);
_scene.lights[1].colour = createVector(0.7, 0.3, 0.3);
_scene.lights[2] = createVector(23, 20, 17);
_scene.lights[2].colour = createVector(0.7, 0.7, 0.7);
_scene.ambient = createVector(0.1, 0.1, 0.1);
// _scene.background = createVector(0.7, 0.7, 1.0);
var size = 30;
var pixels = new Array();
for (var y = 0; y < size; y++) {
pixels[y] = new Array();
for (var x = 0; x < size; x++) {
pixels[y][x] = 0;
}
}
var _camera = new Camera(createVector(-40, 40, 40), createVector(0, 0, 0), createVector(0, 1, 0));
_camera.render(_scene, pixels, size, size);
return pixels;
}
function arrayToCanvasCommands(pixels)
{
var s = '<canvas id="renderCanvas" width="30px" height="30px"></canvas><scr' + 'ipt>\nvar pixels = [';
var size = 30;
for (var y = 0; y < size; y++) {
s += "[";
for (var x = 0; x < size; x++) {
s += "[" + pixels[y][x] + "],";
}
s+= "],";
}
s += '];\n var canvas = document.getElementById("renderCanvas").getContext("2d");\n\
\n\
\n\
var size = 30;\n\
canvas.fillStyle = "red";\n\
canvas.fillRect(0, 0, size, size);\n\
canvas.scale(1, -1);\n\
canvas.translate(0, -size);\n\
\n\
if (!canvas.setFillColor)\n\
canvas.setFillColor = function(r, g, b, a) {\n\
this.fillStyle = "rgb("+[Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)]+")";\n\
}\n\
\n\
for (var y = 0; y < size; y++) {\n\
for (var x = 0; x < size; x++) {\n\
var l = pixels[y][x];\n\
canvas.setFillColor(l[0], l[1], l[2], 1);\n\
canvas.fillRect(x, y, 1, 1);\n\
}\n\
}</scr' + 'ipt>';
return s;
}
testOutput = arrayToCanvasCommands(raytraceScene());

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

@ -0,0 +1,50 @@
/* The Great Computer Language Shootout
http://shootout.alioth.debian.org/
contributed by Isaac Gouy */
function TreeNode(left,right,item){
this.left = left;
this.right = right;
this.item = item;
}
TreeNode.prototype.itemCheck = function(){
if (this.left==null) return this.item;
else return this.item + this.left.itemCheck() - this.right.itemCheck();
}
function bottomUpTree(item,depth){
if (depth>0){
return new TreeNode(
bottomUpTree(2*item-1, depth-1)
,bottomUpTree(2*item, depth-1)
,item
);
}
else {
return new TreeNode(null,null,item);
}
}
var ret;
for ( var n = 4; n <= 7; n += 1 ) {
var minDepth = 4;
var maxDepth = Math.max(minDepth + 2, n);
var stretchDepth = maxDepth + 1;
var check = bottomUpTree(0,stretchDepth).itemCheck();
var longLivedTree = bottomUpTree(0,maxDepth);
for (var depth=minDepth; depth<=maxDepth; depth+=2){
var iterations = 1 << (maxDepth - depth + minDepth);
check = 0;
for (var i=1; i<=iterations; i++){
check += bottomUpTree(i,depth).itemCheck();
check += bottomUpTree(-i,depth).itemCheck();
}
}
ret = longLivedTree.itemCheck();
}

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

@ -0,0 +1,66 @@
/* The Great Computer Language Shootout
http://shootout.alioth.debian.org/
contributed by Isaac Gouy */
function fannkuch(n) {
var check = 0;
var perm = Array(n);
var perm1 = Array(n);
var count = Array(n);
var maxPerm = Array(n);
var maxFlipsCount = 0;
var m = n - 1;
for (var i = 0; i < n; i++) perm1[i] = i;
var r = n;
while (true) {
// write-out the first 30 permutations
if (check < 30){
var s = "";
for(var i=0; i<n; i++) s += (perm1[i]+1).toString();
check++;
}
while (r != 1) { count[r - 1] = r; r--; }
if (!(perm1[0] == 0 || perm1[m] == m)) {
for (var i = 0; i < n; i++) perm[i] = perm1[i];
var flipsCount = 0;
var k;
while (!((k = perm[0]) == 0)) {
var k2 = (k + 1) >> 1;
for (var i = 0; i < k2; i++) {
var temp = perm[i]; perm[i] = perm[k - i]; perm[k - i] = temp;
}
flipsCount++;
}
if (flipsCount > maxFlipsCount) {
maxFlipsCount = flipsCount;
for (var i = 0; i < n; i++) maxPerm[i] = perm1[i];
}
}
while (true) {
if (r == n) return maxFlipsCount;
var perm0 = perm1[0];
var i = 0;
while (i < r) {
var j = i + 1;
perm1[i] = perm1[j];
i = j;
}
perm1[r] = perm0;
count[r] = count[r] - 1;
if (count[r] > 0) break;
r++;
}
}
}
var n = 8;
var ret = fannkuch(n);

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

@ -0,0 +1,169 @@
/* The Great Computer Language Shootout
http://shootout.alioth.debian.org/
contributed by Isaac Gouy */
var PI = 3.141592653589793;
var SOLAR_MASS = 4 * PI * PI;
var DAYS_PER_YEAR = 365.24;
function Body(x,y,z,vx,vy,vz,mass){
this.x = x;
this.y = y;
this.z = z;
this.vx = vx;
this.vy = vy;
this.vz = vz;
this.mass = mass;
}
Body.prototype.offsetMomentum = function(px,py,pz) {
this.vx = -px / SOLAR_MASS;
this.vy = -py / SOLAR_MASS;
this.vz = -pz / SOLAR_MASS;
return this;
}
function Jupiter(){
return new Body(
4.84143144246472090e+00,
-1.16032004402742839e+00,
-1.03622044471123109e-01,
1.66007664274403694e-03 * DAYS_PER_YEAR,
7.69901118419740425e-03 * DAYS_PER_YEAR,
-6.90460016972063023e-05 * DAYS_PER_YEAR,
9.54791938424326609e-04 * SOLAR_MASS
);
}
function Saturn(){
return new Body(
8.34336671824457987e+00,
4.12479856412430479e+00,
-4.03523417114321381e-01,
-2.76742510726862411e-03 * DAYS_PER_YEAR,
4.99852801234917238e-03 * DAYS_PER_YEAR,
2.30417297573763929e-05 * DAYS_PER_YEAR,
2.85885980666130812e-04 * SOLAR_MASS
);
}
function Uranus(){
return new Body(
1.28943695621391310e+01,
-1.51111514016986312e+01,
-2.23307578892655734e-01,
2.96460137564761618e-03 * DAYS_PER_YEAR,
2.37847173959480950e-03 * DAYS_PER_YEAR,
-2.96589568540237556e-05 * DAYS_PER_YEAR,
4.36624404335156298e-05 * SOLAR_MASS
);
}
function Neptune(){
return new Body(
1.53796971148509165e+01,
-2.59193146099879641e+01,
1.79258772950371181e-01,
2.68067772490389322e-03 * DAYS_PER_YEAR,
1.62824170038242295e-03 * DAYS_PER_YEAR,
-9.51592254519715870e-05 * DAYS_PER_YEAR,
5.15138902046611451e-05 * SOLAR_MASS
);
}
function Sun(){
return new Body(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, SOLAR_MASS);
}
function NBodySystem(bodies){
this.bodies = bodies;
var px = 0.0;
var py = 0.0;
var pz = 0.0;
var size = this.bodies.length;
for (var i=0; i<size; i++){
var b = this.bodies[i];
var m = b.mass;
px += b.vx * m;
py += b.vy * m;
pz += b.vz * m;
}
this.bodies[0].offsetMomentum(px,py,pz);
}
NBodySystem.prototype.advance = function(dt){
var dx, dy, dz, distance, mag;
var size = this.bodies.length;
for (var i=0; i<size; i++) {
var bodyi = this.bodies[i];
for (var j=i+1; j<size; j++) {
var bodyj = this.bodies[j];
dx = bodyi.x - bodyj.x;
dy = bodyi.y - bodyj.y;
dz = bodyi.z - bodyj.z;
distance = Math.sqrt(dx*dx + dy*dy + dz*dz);
mag = dt / (distance * distance * distance);
bodyi.vx -= dx * bodyj.mass * mag;
bodyi.vy -= dy * bodyj.mass * mag;
bodyi.vz -= dz * bodyj.mass * mag;
bodyj.vx += dx * bodyi.mass * mag;
bodyj.vy += dy * bodyi.mass * mag;
bodyj.vz += dz * bodyi.mass * mag;
}
}
for (var i=0; i<size; i++) {
var body = this.bodies[i];
body.x += dt * body.vx;
body.y += dt * body.vy;
body.z += dt * body.vz;
}
}
NBodySystem.prototype.energy = function(){
var dx, dy, dz, distance;
var e = 0.0;
var size = this.bodies.length;
for (var i=0; i<size; i++) {
var bodyi = this.bodies[i];
e += 0.5 * bodyi.mass *
( bodyi.vx * bodyi.vx
+ bodyi.vy * bodyi.vy
+ bodyi.vz * bodyi.vz );
for (var j=i+1; j<size; j++) {
var bodyj = this.bodies[j];
dx = bodyi.x - bodyj.x;
dy = bodyi.y - bodyj.y;
dz = bodyi.z - bodyj.z;
distance = Math.sqrt(dx*dx + dy*dy + dz*dz);
e -= (bodyi.mass * bodyj.mass) / distance;
}
}
return e;
}
var ret;
for ( var n = 3; n <= 24; n *= 2 ) {
(function(){
var bodies = new NBodySystem( Array(
Sun(),Jupiter(),Saturn(),Uranus(),Neptune()
));
var max = n * 100;
ret = bodies.energy();
for (var i=0; i<max; i++){
bodies.advance(0.01);
}
ret = bodies.energy();
})();
}

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

@ -0,0 +1,38 @@
// The Great Computer Language Shootout
// http://shootout.alioth.debian.org/
//
// modified by Isaac Gouy
function pad(number,width){
var s = number.toString();
var prefixWidth = width - s.length;
if (prefixWidth>0){
for (var i=1; i<=prefixWidth; i++) s = " " + s;
}
return s;
}
function nsieve(m, isPrime){
var i, k, count;
for (i=2; i<=m; i++) { isPrime[i] = true; }
count = 0;
for (i=2; i<=m; i++){
if (isPrime[i]) {
for (k=i+i; k<=m; k+=i) isPrime[k] = false;
count++;
}
}
return count;
}
function sieve() {
for (var i = 1; i <= 3; i++ ) {
var m = (1<<i)*10000;
var flags = Array(m+1);
nsieve(m, flags);
}
}
sieve();

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

@ -0,0 +1,32 @@
// Copyright (c) 2004 by Arthur Langereis (arthur_ext at domain xfinitegames, tld com
// 1 op = 6 ANDs, 3 SHRs, 3 SHLs, 4 assigns, 2 ADDs
// O(1)
function fast3bitlookup(b) {
var c, bi3b = 0xE994; // 0b1110 1001 1001 0100; // 3 2 2 1 2 1 1 0
c = 3 & (bi3b >> ((b << 1) & 14));
c += 3 & (bi3b >> ((b >> 2) & 14));
c += 3 & (bi3b >> ((b >> 5) & 6));
return c;
/*
lir4,0xE994; 9 instructions, no memory access, minimal register dependence, 6 shifts, 2 adds, 1 inline assign
rlwinmr5,r3,1,28,30
rlwinmr6,r3,30,28,30
rlwinmr7,r3,27,29,30
rlwnmr8,r4,r5,30,31
rlwnmr9,r4,r6,30,31
rlwnmr10,r4,r7,30,31
addr3,r8,r9
addr3,r3,r10
*/
}
function TimeFunc(func) {
var x, y, t;
for(var x=0; x<500; x++)
for(var y=0; y<256; y++) func(y);
}
TimeFunc(fast3bitlookup);

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

@ -0,0 +1,21 @@
// Copyright (c) 2004 by Arthur Langereis (arthur_ext at domain xfinitegames, tld com)
// 1 op = 2 assigns, 16 compare/branches, 8 ANDs, (0-8) ADDs, 8 SHLs
// O(n)
function bitsinbyte(b) {
var m = 1, c = 0;
while(m<0x100) {
if(b & m) c++;
m <<= 1;
}
return c;
}
function TimeFunc(func) {
var x, y, t;
for(var x=0; x<350; x++)
for(var y=0; y<256; y++) func(y);
}
TimeFunc(bitsinbyte);

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

@ -0,0 +1,28 @@
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
bitwiseAndValue = 4294967296;
for (var i = 0; i < 600000; i++)
bitwiseAndValue = bitwiseAndValue & i;

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

@ -0,0 +1,32 @@
// The Great Computer Language Shootout
// http://shootout.alioth.debian.org
//
// Contributed by Ian Osgood
function pad(n,width) {
var s = n.toString();
while (s.length < width) s = ' ' + s;
return s;
}
function primes(isPrime, n) {
var i, count = 0, m = 10000<<n, size = m+31>>5;
for (i=0; i<size; i++) isPrime[i] = 0xffffffff;
for (i=2; i<m; i++)
if (isPrime[i>>5] & 1<<(i&31)) {
for (var j=i+i; j<m; j+=i)
isPrime[j>>5] &= ~(1<<(j&31));
count++;
}
}
function sieve() {
for (var i = 4; i <= 4; i++) {
var isPrime = new Array((10000<<i)+31>>5);
primes(isPrime, i);
}
}
sieve();

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

@ -0,0 +1,25 @@
// The Computer Language Shootout
// http://shootout.alioth.debian.org/
// contributed by Isaac Gouy
function ack(m,n){
if (m==0) { return n+1; }
if (n==0) { return ack(m-1,1); }
return ack(m-1, ack(m,n-1) );
}
function fib(n) {
if (n < 2){ return 1; }
return fib(n-2) + fib(n-1);
}
function tak(x,y,z) {
if (y >= x) return z;
return tak(tak(x-1,y,z), tak(y-1,z,x), tak(z-1,x,y));
}
for ( var i = 3; i <= 5; i++ ) {
ack(3,i);
fib(17.0+i);
tak(3*i+3,2*i+2,i+1);
}

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

@ -0,0 +1,422 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* AES Cipher function: encrypt 'input' with Rijndael algorithm
*
* takes byte-array 'input' (16 bytes)
* 2D byte-array key schedule 'w' (Nr+1 x Nb bytes)
*
* applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage
*
* returns byte-array encrypted value (16 bytes)
*/
function Cipher(input, w) { // main Cipher function [§5.1]
var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
var state = [[],[],[],[]]; // initialise 4xNb byte-array 'state' with input [§3.4]
for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i];
state = AddRoundKey(state, w, 0, Nb);
for (var round=1; round<Nr; round++) {
state = SubBytes(state, Nb);
state = ShiftRows(state, Nb);
state = MixColumns(state, Nb);
state = AddRoundKey(state, w, round, Nb);
}
state = SubBytes(state, Nb);
state = ShiftRows(state, Nb);
state = AddRoundKey(state, w, Nr, Nb);
var output = new Array(4*Nb); // convert state to 1-d array before returning [§3.4]
for (var i=0; i<4*Nb; i++) output[i] = state[i%4][Math.floor(i/4)];
return output;
}
function SubBytes(s, Nb) { // apply SBox to state S [§5.1.1]
for (var r=0; r<4; r++) {
for (var c=0; c<Nb; c++) s[r][c] = Sbox[s[r][c]];
}
return s;
}
function ShiftRows(s, Nb) { // shift row r of state S left by r bytes [§5.1.2]
var t = new Array(4);
for (var r=1; r<4; r++) {
for (var c=0; c<4; c++) t[c] = s[r][(c+r)%Nb]; // shift into temp copy
for (var c=0; c<4; c++) s[r][c] = t[c]; // and copy back
} // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
return s; // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
}
function MixColumns(s, Nb) { // combine bytes of each col of state S [§5.1.3]
for (var c=0; c<4; c++) {
var a = new Array(4); // 'a' is a copy of the current column from 's'
var b = new Array(4); // 'b' is a•{02} in GF(2^8)
for (var i=0; i<4; i++) {
a[i] = s[i][c];
b[i] = s[i][c]&0x80 ? s[i][c]<<1 ^ 0x011b : s[i][c]<<1;
}
// a[n] ^ b[n] is a•{03} in GF(2^8)
s[0][c] = b[0] ^ a[1] ^ b[1] ^ a[2] ^ a[3]; // 2*a0 + 3*a1 + a2 + a3
s[1][c] = a[0] ^ b[1] ^ a[2] ^ b[2] ^ a[3]; // a0 * 2*a1 + 3*a2 + a3
s[2][c] = a[0] ^ a[1] ^ b[2] ^ a[3] ^ b[3]; // a0 + a1 + 2*a2 + 3*a3
s[3][c] = a[0] ^ b[0] ^ a[1] ^ a[2] ^ b[3]; // 3*a0 + a1 + a2 + 2*a3
}
return s;
}
function AddRoundKey(state, w, rnd, Nb) { // xor Round Key into state S [§5.1.4]
for (var r=0; r<4; r++) {
for (var c=0; c<Nb; c++) state[r][c] ^= w[rnd*4+c][r];
}
return state;
}
function KeyExpansion(key) { // generate Key Schedule (byte-array Nr+1 x Nb) from Key [§5.2]
var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
var Nk = key.length/4 // key length (in words): 4/6/8 for 128/192/256-bit keys
var Nr = Nk + 6; // no of rounds: 10/12/14 for 128/192/256-bit keys
var w = new Array(Nb*(Nr+1));
var temp = new Array(4);
for (var i=0; i<Nk; i++) {
var r = [key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]];
w[i] = r;
}
for (var i=Nk; i<(Nb*(Nr+1)); i++) {
w[i] = new Array(4);
for (var t=0; t<4; t++) temp[t] = w[i-1][t];
if (i % Nk == 0) {
temp = SubWord(RotWord(temp));
for (var t=0; t<4; t++) temp[t] ^= Rcon[i/Nk][t];
} else if (Nk > 6 && i%Nk == 4) {
temp = SubWord(temp);
}
for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t];
}
return w;
}
function SubWord(w) { // apply SBox to 4-byte word w
for (var i=0; i<4; i++) w[i] = Sbox[w[i]];
return w;
}
function RotWord(w) { // rotate 4-byte word w left by one byte
w[4] = w[0];
for (var i=0; i<4; i++) w[i] = w[i+1];
return w;
}
// Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [§5.1.1]
var Sbox = [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16];
// Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2]
var Rcon = [ [0x00, 0x00, 0x00, 0x00],
[0x01, 0x00, 0x00, 0x00],
[0x02, 0x00, 0x00, 0x00],
[0x04, 0x00, 0x00, 0x00],
[0x08, 0x00, 0x00, 0x00],
[0x10, 0x00, 0x00, 0x00],
[0x20, 0x00, 0x00, 0x00],
[0x40, 0x00, 0x00, 0x00],
[0x80, 0x00, 0x00, 0x00],
[0x1b, 0x00, 0x00, 0x00],
[0x36, 0x00, 0x00, 0x00] ];
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Use AES to encrypt 'plaintext' with 'password' using 'nBits' key, in 'Counter' mode of operation
* - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
* for each block
* - outputblock = cipher(counter, key)
* - cipherblock = plaintext xor outputblock
*/
function AESEncryptCtr(plaintext, password, nBits) {
if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys
// for this example script, generate the key by applying Cipher to 1st 16/24/32 chars of password;
// for real-world applications, a more secure approach would be to hash the password e.g. with SHA-1
var nBytes = nBits/8; // no bytes in key
var pwBytes = new Array(nBytes);
for (var i=0; i<nBytes; i++) pwBytes[i] = password.charCodeAt(i) & 0xff;
var key = Cipher(pwBytes, KeyExpansion(pwBytes));
key = key.concat(key.slice(0, nBytes-16)); // key is now 16/24/32 bytes long
// initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in 1st 8 bytes,
// block counter in 2nd 8 bytes
var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
var counterBlock = new Array(blockSize); // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
var nonce = (new Date()).getTime(); // milliseconds since 1-Jan-1970
// encode nonce in two stages to cater for JavaScript 32-bit limit on bitwise ops
for (var i=0; i<4; i++) counterBlock[i] = (nonce >>> i*8) & 0xff;
for (var i=0; i<4; i++) counterBlock[i+4] = (nonce/0x100000000 >>> i*8) & 0xff;
// generate key schedule - an expansion of the key into distinct Key Rounds for each round
var keySchedule = KeyExpansion(key);
var blockCount = Math.ceil(plaintext.length/blockSize);
var ciphertext = new Array(blockCount); // ciphertext as array of strings
for (var b=0; b<blockCount; b++) {
// set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
// again done in two stages for 32-bit ops
for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff;
for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8)
var cipherCntr = Cipher(counterBlock, keySchedule); // -- encrypt counter block --
// calculate length of final block:
var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1;
var ct = '';
for (var i=0; i<blockLength; i++) { // -- xor plaintext with ciphered counter byte-by-byte --
var plaintextByte = plaintext.charCodeAt(b*blockSize+i);
var cipherByte = plaintextByte ^ cipherCntr[i];
ct += String.fromCharCode(cipherByte);
}
// ct is now ciphertext for this block
ciphertext[b] = escCtrlChars(ct); // escape troublesome characters in ciphertext
}
// convert the nonce to a string to go on the front of the ciphertext
var ctrTxt = '';
for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]);
ctrTxt = escCtrlChars(ctrTxt);
// use '-' to separate blocks, use Array.join to concatenate arrays of strings for efficiency
return ctrTxt + '-' + ciphertext.join('-');
}
/*
* Use AES to decrypt 'ciphertext' with 'password' using 'nBits' key, in Counter mode of operation
*
* for each block
* - outputblock = cipher(counter, key)
* - cipherblock = plaintext xor outputblock
*/
function AESDecryptCtr(ciphertext, password, nBits) {
if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys
var nBytes = nBits/8; // no bytes in key
var pwBytes = new Array(nBytes);
for (var i=0; i<nBytes; i++) pwBytes[i] = password.charCodeAt(i) & 0xff;
var pwKeySchedule = KeyExpansion(pwBytes);
var key = Cipher(pwBytes, pwKeySchedule);
key = key.concat(key.slice(0, nBytes-16)); // key is now 16/24/32 bytes long
var keySchedule = KeyExpansion(key);
ciphertext = ciphertext.split('-'); // split ciphertext into array of block-length strings
// recover nonce from 1st element of ciphertext
var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
var counterBlock = new Array(blockSize);
var ctrTxt = unescCtrlChars(ciphertext[0]);
for (var i=0; i<8; i++) counterBlock[i] = ctrTxt.charCodeAt(i);
var plaintext = new Array(ciphertext.length-1);
for (var b=1; b<ciphertext.length; b++) {
// set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
for (var c=0; c<4; c++) counterBlock[15-c] = ((b-1) >>> c*8) & 0xff;
for (var c=0; c<4; c++) counterBlock[15-c-4] = ((b/0x100000000-1) >>> c*8) & 0xff;
var cipherCntr = Cipher(counterBlock, keySchedule); // encrypt counter block
ciphertext[b] = unescCtrlChars(ciphertext[b]);
var pt = '';
for (var i=0; i<ciphertext[b].length; i++) {
// -- xor plaintext with ciphered counter byte-by-byte --
var ciphertextByte = ciphertext[b].charCodeAt(i);
var plaintextByte = ciphertextByte ^ cipherCntr[i];
pt += String.fromCharCode(plaintextByte);
}
// pt is now plaintext for this block
plaintext[b-1] = pt; // b-1 'cos no initial nonce block in plaintext
}
return plaintext.join('');
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
function escCtrlChars(str) { // escape control chars which might cause problems handling ciphertext
return str.replace(/[\0\t\n\v\f\r\xa0'"!-]/g, function(c) { return '!' + c.charCodeAt(0) + '!'; });
} // \xa0 to cater for bug in Firefox; include '-' to leave it free for use as a block marker
function unescCtrlChars(str) { // unescape potentially problematic control characters
return str.replace(/!\d\d?\d?!/g, function(c) { return String.fromCharCode(c.slice(1,-1)); });
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* if escCtrlChars()/unescCtrlChars() still gives problems, use encodeBase64()/decodeBase64() instead
*/
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
function encodeBase64(str) { // http://tools.ietf.org/html/rfc4648
var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
str = encodeUTF8(str); // encode multi-byte chars into UTF-8 for byte-array
do { // pack three octets into four hexets
o1 = str.charCodeAt(i++);
o2 = str.charCodeAt(i++);
o3 = str.charCodeAt(i++);
bits = o1<<16 | o2<<8 | o3;
h1 = bits>>18 & 0x3f;
h2 = bits>>12 & 0x3f;
h3 = bits>>6 & 0x3f;
h4 = bits & 0x3f;
// end of string? index to '=' in b64
if (isNaN(o3)) h4 = 64;
if (isNaN(o2)) h3 = 64;
// use hexets to index into b64, and append result to encoded string
enc += b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
} while (i < str.length);
return enc;
}
function decodeBase64(str) {
var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
do { // unpack four hexets into three octets using index points in b64
h1 = b64.indexOf(str.charAt(i++));
h2 = b64.indexOf(str.charAt(i++));
h3 = b64.indexOf(str.charAt(i++));
h4 = b64.indexOf(str.charAt(i++));
bits = h1<<18 | h2<<12 | h3<<6 | h4;
o1 = bits>>16 & 0xff;
o2 = bits>>8 & 0xff;
o3 = bits & 0xff;
if (h3 == 64) enc += String.fromCharCode(o1);
else if (h4 == 64) enc += String.fromCharCode(o1, o2);
else enc += String.fromCharCode(o1, o2, o3);
} while (i < str.length);
return decodeUTF8(enc); // decode UTF-8 byte-array back to Unicode
}
function encodeUTF8(str) { // encode multi-byte string into utf-8 multiple single-byte characters
str = str.replace(
/[\u0080-\u07ff]/g, // U+0080 - U+07FF = 2-byte chars
function(c) {
var cc = c.charCodeAt(0);
return String.fromCharCode(0xc0 | cc>>6, 0x80 | cc&0x3f); }
);
str = str.replace(
/[\u0800-\uffff]/g, // U+0800 - U+FFFF = 3-byte chars
function(c) {
var cc = c.charCodeAt(0);
return String.fromCharCode(0xe0 | cc>>12, 0x80 | cc>>6&0x3F, 0x80 | cc&0x3f); }
);
return str;
}
function decodeUTF8(str) { // decode utf-8 encoded string back into multi-byte characters
str = str.replace(
/[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars
function(c) {
var cc = (c.charCodeAt(0)&0x1f)<<6 | c.charCodeAt(1)&0x3f;
return String.fromCharCode(cc); }
);
str = str.replace(
/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars
function(c) {
var cc = (c.charCodeAt(0)&0x0f)<<12 | (c.charCodeAt(1)&0x3f<<6) | c.charCodeAt(2)&0x3f;
return String.fromCharCode(cc); }
);
return str;
}
function byteArrayToHexStr(b) { // convert byte array to hex string for displaying test vectors
var s = '';
for (var i=0; i<b.length; i++) s += b[i].toString(16) + ' ';
return s;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
var plainText = "ROMEO: But, soft! what light through yonder window breaks?\n\
It is the east, and Juliet is the sun.\n\
Arise, fair sun, and kill the envious moon,\n\
Who is already sick and pale with grief,\n\
That thou her maid art far more fair than she:\n\
Be not her maid, since she is envious;\n\
Her vestal livery is but sick and green\n\
And none but fools do wear it; cast it off.\n\
It is my lady, O, it is my love!\n\
O, that she knew she were!\n\
She speaks yet she says nothing: what of that?\n\
Her eye discourses; I will answer it.\n\
I am too bold, 'tis not to me she speaks:\n\
Two of the fairest stars in all the heaven,\n\
Having some business, do entreat her eyes\n\
To twinkle in their spheres till they return.\n\
What if her eyes were there, they in her head?\n\
The brightness of her cheek would shame those stars,\n\
As daylight doth a lamp; her eyes in heaven\n\
Would through the airy region stream so bright\n\
That birds would sing and think it were not night.\n\
See, how she leans her cheek upon her hand!\n\
O, that I were a glove upon that hand,\n\
That I might touch that cheek!\n\
JULIET: Ay me!\n\
ROMEO: She speaks:\n\
O, speak again, bright angel! for thou art\n\
As glorious to this night, being o'er my head\n\
As is a winged messenger of heaven\n\
Unto the white-upturned wondering eyes\n\
Of mortals that fall back to gaze on him\n\
When he bestrides the lazy-pacing clouds\n\
And sails upon the bosom of the air.";
var password = "O Romeo, Romeo! wherefore art thou Romeo?";
var cipherText = AESEncryptCtr(plainText, password, 256);
var decryptedText = AESDecryptCtr(cipherText, password, 256);

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

@ -0,0 +1,286 @@
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
*/
/*
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
/*
* Perform a simple self-test to see if the VM is working
*/
function md5_vm_test()
{
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length
*/
function core_md5(x, len)
{
/* append padding */
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return Array(a, b, c, d);
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
function md5_cmn(q, a, b, x, s, t)
{
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}
/*
* Calculate the HMAC-MD5, of a key and some data
*/
function core_hmac_md5(key, data)
{
var bkey = str2binl(key);
if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
var ipad = Array(16), opad = Array(16);
for(var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
return core_md5(opad.concat(hash), 512 + 128);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function bit_rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Convert a string to an array of little-endian words
* If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
*/
function str2binl(str)
{
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i += chrsz)
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
return bin;
}
/*
* Convert an array of little-endian words to a string
*/
function binl2str(bin)
{
var str = "";
var mask = (1 << chrsz) - 1;
for(var i = 0; i < bin.length * 32; i += chrsz)
str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
return str;
}
/*
* Convert an array of little-endian words to a hex string.
*/
function binl2hex(binarray)
{
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
}
return str;
}
/*
* Convert an array of little-endian words to a base-64 string
*/
function binl2b64(binarray)
{
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for(var i = 0; i < binarray.length * 4; i += 3)
{
var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)
| (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
| ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
for(var j = 0; j < 4; j++)
{
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
}
}
return str;
}
var plainText = "Rebellious subjects, enemies to peace,\n\
Profaners of this neighbour-stained steel,--\n\
Will they not hear? What, ho! you men, you beasts,\n\
That quench the fire of your pernicious rage\n\
With purple fountains issuing from your veins,\n\
On pain of torture, from those bloody hands\n\
Throw your mistemper'd weapons to the ground,\n\
And hear the sentence of your moved prince.\n\
Three civil brawls, bred of an airy word,\n\
By thee, old Capulet, and Montague,\n\
Have thrice disturb'd the quiet of our streets,\n\
And made Verona's ancient citizens\n\
Cast by their grave beseeming ornaments,\n\
To wield old partisans, in hands as old,\n\
Canker'd with peace, to part your canker'd hate:\n\
If ever you disturb our streets again,\n\
Your lives shall pay the forfeit of the peace.\n\
For this time, all the rest depart away:\n\
You Capulet; shall go along with me:\n\
And, Montague, come you this afternoon,\n\
To know our further pleasure in this case,\n\
To old Free-town, our common judgment-place.\n\
Once more, on pain of death, all men depart."
for (var i = 0; i <4; i++) {
plainText += plainText;
}
var md5Output = hex_md5(plainText);

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

@ -0,0 +1,224 @@
/*
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
* in FIPS PUB 180-1
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for details.
*/
/*
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
/*
* Perform a simple self-test to see if the VM is working
*/
function sha1_vm_test()
{
return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
}
/*
* Calculate the SHA-1 of an array of big-endian words, and a bit length
*/
function core_sha1(x, len)
{
/* append padding */
x[len >> 5] |= 0x80 << (24 - len % 32);
x[((len + 64 >> 9) << 4) + 15] = len;
var w = Array(80);
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
var e = -1009589776;
for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
var olde = e;
for(var j = 0; j < 80; j++)
{
if(j < 16) w[j] = x[i + j];
else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
safe_add(safe_add(e, w[j]), sha1_kt(j)));
e = d;
d = c;
c = rol(b, 30);
b = a;
a = t;
}
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
e = safe_add(e, olde);
}
return Array(a, b, c, d, e);
}
/*
* Perform the appropriate triplet combination function for the current
* iteration
*/
function sha1_ft(t, b, c, d)
{
if(t < 20) return (b & c) | ((~b) & d);
if(t < 40) return b ^ c ^ d;
if(t < 60) return (b & c) | (b & d) | (c & d);
return b ^ c ^ d;
}
/*
* Determine the appropriate additive constant for the current iteration
*/
function sha1_kt(t)
{
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
(t < 60) ? -1894007588 : -899497514;
}
/*
* Calculate the HMAC-SHA1 of a key and some data
*/
function core_hmac_sha1(key, data)
{
var bkey = str2binb(key);
if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
var ipad = Array(16), opad = Array(16);
for(var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
return core_sha1(opad.concat(hash), 512 + 160);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Convert an 8-bit or 16-bit string to an array of big-endian words
* In 8-bit function, characters >255 have their hi-byte silently ignored.
*/
function str2binb(str)
{
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i += chrsz)
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
return bin;
}
/*
* Convert an array of big-endian words to a string
*/
function binb2str(bin)
{
var str = "";
var mask = (1 << chrsz) - 1;
for(var i = 0; i < bin.length * 32; i += chrsz)
str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
return str;
}
/*
* Convert an array of big-endian words to a hex string.
*/
function binb2hex(binarray)
{
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
}
return str;
}
/*
* Convert an array of big-endian words to a base-64 string
*/
function binb2b64(binarray)
{
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for(var i = 0; i < binarray.length * 4; i += 3)
{
var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16)
| (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
| ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
for(var j = 0; j < 4; j++)
{
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
}
}
return str;
}
var plainText = "Two households, both alike in dignity,\n\
In fair Verona, where we lay our scene,\n\
From ancient grudge break to new mutiny,\n\
Where civil blood makes civil hands unclean.\n\
From forth the fatal loins of these two foes\n\
A pair of star-cross'd lovers take their life;\n\
Whole misadventured piteous overthrows\n\
Do with their death bury their parents' strife.\n\
The fearful passage of their death-mark'd love,\n\
And the continuance of their parents' rage,\n\
Which, but their children's end, nought could remove,\n\
Is now the two hours' traffic of our stage;\n\
The which if you with patient ears attend,\n\
What here shall miss, our toil shall strive to mend.";
for (var i = 0; i <4; i++) {
plainText += plainText;
}
var sha1Output = hex_sha1(plainText);

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

@ -0,0 +1,299 @@
function arrayExists(array, x) {
for (var i = 0; i < array.length; i++) {
if (array[i] == x) return true;
}
return false;
}
Date.prototype.formatDate = function (input,time) {
// formatDate :
// a PHP date like function, for formatting date strings
// See: http://www.php.net/date
//
// input : format string
// time : epoch time (seconds, and optional)
//
// if time is not passed, formatting is based on
// the current "this" date object's set time.
//
// supported:
// a, A, B, d, D, F, g, G, h, H, i, j, l (lowercase L), L,
// m, M, n, O, r, s, S, t, U, w, W, y, Y, z
//
// unsupported:
// I (capital i), T, Z
var switches = ["a", "A", "B", "d", "D", "F", "g", "G", "h", "H",
"i", "j", "l", "L", "m", "M", "n", "O", "r", "s",
"S", "t", "U", "w", "W", "y", "Y", "z"];
var daysLong = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
var daysShort = ["Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat"];
var monthsShort = ["Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"];
var monthsLong = ["January", "February", "March", "April",
"May", "June", "July", "August", "September",
"October", "November", "December"];
var daysSuffix = ["st", "nd", "rd", "th", "th", "th", "th", // 1st - 7th
"th", "th", "th", "th", "th", "th", "th", // 8th - 14th
"th", "th", "th", "th", "th", "th", "st", // 15th - 21st
"nd", "rd", "th", "th", "th", "th", "th", // 22nd - 28th
"th", "th", "st"]; // 29th - 31st
function a() {
// Lowercase Ante meridiem and Post meridiem
return self.getHours() > 11? "pm" : "am";
}
function A() {
// Uppercase Ante meridiem and Post meridiem
return self.getHours() > 11? "PM" : "AM";
}
function B(){
// Swatch internet time. code simply grabbed from ppk,
// since I was feeling lazy:
// http://www.xs4all.nl/~ppk/js/beat.html
var off = (self.getTimezoneOffset() + 60)*60;
var theSeconds = (self.getHours() * 3600) +
(self.getMinutes() * 60) +
self.getSeconds() + off;
var beat = Math.floor(theSeconds/86.4);
if (beat > 1000) beat -= 1000;
if (beat < 0) beat += 1000;
if ((""+beat).length == 1) beat = "00"+beat;
if ((""+beat).length == 2) beat = "0"+beat;
return beat;
}
function d() {
// Day of the month, 2 digits with leading zeros
return new String(self.getDate()).length == 1?
"0"+self.getDate() : self.getDate();
}
function D() {
// A textual representation of a day, three letters
return daysShort[self.getDay()];
}
function F() {
// A full textual representation of a month
return monthsLong[self.getMonth()];
}
function g() {
// 12-hour format of an hour without leading zeros
return self.getHours() > 12? self.getHours()-12 : self.getHours();
}
function G() {
// 24-hour format of an hour without leading zeros
return self.getHours();
}
function h() {
// 12-hour format of an hour with leading zeros
if (self.getHours() > 12) {
var s = new String(self.getHours()-12);
return s.length == 1?
"0"+ (self.getHours()-12) : self.getHours()-12;
} else {
var s = new String(self.getHours());
return s.length == 1?
"0"+self.getHours() : self.getHours();
}
}
function H() {
// 24-hour format of an hour with leading zeros
return new String(self.getHours()).length == 1?
"0"+self.getHours() : self.getHours();
}
function i() {
// Minutes with leading zeros
return new String(self.getMinutes()).length == 1?
"0"+self.getMinutes() : self.getMinutes();
}
function j() {
// Day of the month without leading zeros
return self.getDate();
}
function l() {
// A full textual representation of the day of the week
return daysLong[self.getDay()];
}
function L() {
// leap year or not. 1 if leap year, 0 if not.
// the logic should match iso's 8601 standard.
var y_ = Y();
if (
(y_ % 4 == 0 && y_ % 100 != 0) ||
(y_ % 4 == 0 && y_ % 100 == 0 && y_ % 400 == 0)
) {
return 1;
} else {
return 0;
}
}
function m() {
// Numeric representation of a month, with leading zeros
return self.getMonth() < 9?
"0"+(self.getMonth()+1) :
self.getMonth()+1;
}
function M() {
// A short textual representation of a month, three letters
return monthsShort[self.getMonth()];
}
function n() {
// Numeric representation of a month, without leading zeros
return self.getMonth()+1;
}
function O() {
// Difference to Greenwich time (GMT) in hours
var os = Math.abs(self.getTimezoneOffset());
var h = ""+Math.floor(os/60);
var m = ""+(os%60);
h.length == 1? h = "0"+h:1;
m.length == 1? m = "0"+m:1;
return self.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m;
}
function r() {
// RFC 822 formatted date
var r; // result
// Thu , 21 Dec 2000
r = D() + ", " + j() + " " + M() + " " + Y() +
// 16 : 01 : 07 +0200
" " + H() + ":" + i() + ":" + s() + " " + O();
return r;
}
function S() {
// English ordinal suffix for the day of the month, 2 characters
return daysSuffix[self.getDate()-1];
}
function s() {
// Seconds, with leading zeros
return new String(self.getSeconds()).length == 1?
"0"+self.getSeconds() : self.getSeconds();
}
function t() {
// thanks to Matt Bannon for some much needed code-fixes here!
var daysinmonths = [null,31,28,31,30,31,30,31,31,30,31,30,31];
if (L()==1 && n()==2) return 29; // leap day
return daysinmonths[n()];
}
function U() {
// Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
return Math.round(self.getTime()/1000);
}
function W() {
// Weeknumber, as per ISO specification:
// http://www.cl.cam.ac.uk/~mgk25/iso-time.html
// if the day is three days before newyears eve,
// there's a chance it's "week 1" of next year.
// here we check for that.
var beforeNY = 364+L() - z();
var afterNY = z();
var weekday = w()!=0?w()-1:6; // makes sunday (0), into 6.
if (beforeNY <= 2 && weekday <= 2-beforeNY) {
return 1;
}
// similarly, if the day is within threedays of newyears
// there's a chance it belongs in the old year.
var ny = new Date("January 1 " + Y() + " 00:00:00");
var nyDay = ny.getDay()!=0?ny.getDay()-1:6;
if (
(afterNY <= 2) &&
(nyDay >=4) &&
(afterNY >= (6-nyDay))
) {
// Since I'm not sure we can just always return 53,
// i call the function here again, using the last day
// of the previous year, as the date, and then just
// return that week.
var prevNY = new Date("December 31 " + (Y()-1) + " 00:00:00");
return prevNY.formatDate("W");
}
// week 1, is the week that has the first thursday in it.
// note that this value is not zero index.
if (nyDay <= 3) {
// first day of the year fell on a thursday, or earlier.
return 1 + Math.floor( ( z() + nyDay ) / 7 );
} else {
// first day of the year fell on a friday, or later.
return 1 + Math.floor( ( z() - ( 7 - nyDay ) ) / 7 );
}
}
function w() {
// Numeric representation of the day of the week
return self.getDay();
}
function Y() {
// A full numeric representation of a year, 4 digits
// we first check, if getFullYear is supported. if it
// is, we just use that. ppks code is nice, but wont
// work with dates outside 1900-2038, or something like that
if (self.getFullYear) {
var newDate = new Date("January 1 2001 00:00:00 +0000");
var x = newDate .getFullYear();
if (x == 2001) {
// i trust the method now
return self.getFullYear();
}
}
// else, do this:
// codes thanks to ppk:
// http://www.xs4all.nl/~ppk/js/introdate.html
var x = self.getYear();
var y = x % 100;
y += (y < 38) ? 2000 : 1900;
return y;
}
function y() {
// A two-digit representation of a year
var y = Y()+"";
return y.substring(y.length-2,y.length);
}
function z() {
// The day of the year, zero indexed! 0 through 366
var t = new Date("January 1 " + Y() + " 00:00:00");
var diff = self.getTime() - t.getTime();
return Math.floor(diff/1000/60/60/24);
}
var self = this;
if (time) {
// save time
var prevTime = self.getTime();
self.setTime(time);
}
var ia = input.split("");
var ij = 0;
while (ia[ij]) {
if (ia[ij] == "\\") {
// this is our way of allowing users to escape stuff
ia.splice(ij,1);
} else {
if (arrayExists(switches,ia[ij])) {
ia[ij] = eval(ia[ij] + "()");
}
}
ij++;
}
// reset time, back to what it was
if (prevTime) {
self.setTime(prevTime);
}
return ia.join("");
}
var date = new Date("1/1/2007 1:11:11");
for (i = 0; i < 500; ++i) {
var shortFormat = date.formatDate("Y-m-d");
var longFormat = date.formatDate("l, F d, Y g:i:s A");
date.setTime(date.getTime() + 84266956);
}

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

@ -0,0 +1,417 @@
/*
* Copyright (C) 2004 Baron Schwartz <baron at sequent dot org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, version 2.1.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
Date.parseFunctions = {count:0};
Date.parseRegexes = [];
Date.formatFunctions = {count:0};
Date.prototype.dateFormat = function(format) {
if (Date.formatFunctions[format] == null) {
Date.createNewFormat(format);
}
var func = Date.formatFunctions[format];
return this[func]();
}
Date.createNewFormat = function(format) {
var funcName = "format" + Date.formatFunctions.count++;
Date.formatFunctions[format] = funcName;
var code = "Date.prototype." + funcName + " = function(){return ";
var special = false;
var ch = '';
for (var i = 0; i < format.length; ++i) {
ch = format.charAt(i);
if (!special && ch == "\\") {
special = true;
}
else if (special) {
special = false;
code += "'" + String.escape(ch) + "' + ";
}
else {
code += Date.getFormatCode(ch);
}
}
eval(code.substring(0, code.length - 3) + ";}");
}
Date.getFormatCode = function(character) {
switch (character) {
case "d":
return "String.leftPad(this.getDate(), 2, '0') + ";
case "D":
return "Date.dayNames[this.getDay()].substring(0, 3) + ";
case "j":
return "this.getDate() + ";
case "l":
return "Date.dayNames[this.getDay()] + ";
case "S":
return "this.getSuffix() + ";
case "w":
return "this.getDay() + ";
case "z":
return "this.getDayOfYear() + ";
case "W":
return "this.getWeekOfYear() + ";
case "F":
return "Date.monthNames[this.getMonth()] + ";
case "m":
return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
case "M":
return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
case "n":
return "(this.getMonth() + 1) + ";
case "t":
return "this.getDaysInMonth() + ";
case "L":
return "(this.isLeapYear() ? 1 : 0) + ";
case "Y":
return "this.getFullYear() + ";
case "y":
return "('' + this.getFullYear()).substring(2, 4) + ";
case "a":
return "(this.getHours() < 12 ? 'am' : 'pm') + ";
case "A":
return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
case "g":
return "((this.getHours() %12) ? this.getHours() % 12 : 12) + ";
case "G":
return "this.getHours() + ";
case "h":
return "String.leftPad((this.getHours() %12) ? this.getHours() % 12 : 12, 2, '0') + ";
case "H":
return "String.leftPad(this.getHours(), 2, '0') + ";
case "i":
return "String.leftPad(this.getMinutes(), 2, '0') + ";
case "s":
return "String.leftPad(this.getSeconds(), 2, '0') + ";
case "O":
return "this.getGMTOffset() + ";
case "T":
return "this.getTimezone() + ";
case "Z":
return "(this.getTimezoneOffset() * -60) + ";
default:
return "'" + String.escape(character) + "' + ";
}
}
Date.parseDate = function(input, format) {
if (Date.parseFunctions[format] == null) {
Date.createParser(format);
}
var func = Date.parseFunctions[format];
return Date[func](input);
}
Date.createParser = function(format) {
var funcName = "parse" + Date.parseFunctions.count++;
var regexNum = Date.parseRegexes.length;
var currentGroup = 1;
Date.parseFunctions[format] = funcName;
var code = "Date." + funcName + " = function(input){\n"
+ "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1;\n"
+ "var d = new Date();\n"
+ "y = d.getFullYear();\n"
+ "m = d.getMonth();\n"
+ "d = d.getDate();\n"
+ "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
+ "if (results && results.length > 0) {"
var regex = "";
var special = false;
var ch = '';
for (var i = 0; i < format.length; ++i) {
ch = format.charAt(i);
if (!special && ch == "\\") {
special = true;
}
else if (special) {
special = false;
regex += String.escape(ch);
}
else {
obj = Date.formatCodeToRegex(ch, currentGroup);
currentGroup += obj.g;
regex += obj.s;
if (obj.g && obj.c) {
code += obj.c;
}
}
}
code += "if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
+ "{return new Date(y, m, d, h, i, s);}\n"
+ "else if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
+ "{return new Date(y, m, d, h, i);}\n"
+ "else if (y > 0 && m >= 0 && d > 0 && h >= 0)\n"
+ "{return new Date(y, m, d, h);}\n"
+ "else if (y > 0 && m >= 0 && d > 0)\n"
+ "{return new Date(y, m, d);}\n"
+ "else if (y > 0 && m >= 0)\n"
+ "{return new Date(y, m);}\n"
+ "else if (y > 0)\n"
+ "{return new Date(y);}\n"
+ "}return null;}";
Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
eval(code);
}
Date.formatCodeToRegex = function(character, currentGroup) {
switch (character) {
case "D":
return {g:0,
c:null,
s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
case "j":
case "d":
return {g:1,
c:"d = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{1,2})"};
case "l":
return {g:0,
c:null,
s:"(?:" + Date.dayNames.join("|") + ")"};
case "S":
return {g:0,
c:null,
s:"(?:st|nd|rd|th)"};
case "w":
return {g:0,
c:null,
s:"\\d"};
case "z":
return {g:0,
c:null,
s:"(?:\\d{1,3})"};
case "W":
return {g:0,
c:null,
s:"(?:\\d{2})"};
case "F":
return {g:1,
c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
s:"(" + Date.monthNames.join("|") + ")"};
case "M":
return {g:1,
c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
case "n":
case "m":
return {g:1,
c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
s:"(\\d{1,2})"};
case "t":
return {g:0,
c:null,
s:"\\d{1,2}"};
case "L":
return {g:0,
c:null,
s:"(?:1|0)"};
case "Y":
return {g:1,
c:"y = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{4})"};
case "y":
return {g:1,
c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
+ "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
s:"(\\d{1,2})"};
case "a":
return {g:1,
c:"if (results[" + currentGroup + "] == 'am') {\n"
+ "if (h == 12) { h = 0; }\n"
+ "} else { if (h < 12) { h += 12; }}",
s:"(am|pm)"};
case "A":
return {g:1,
c:"if (results[" + currentGroup + "] == 'AM') {\n"
+ "if (h == 12) { h = 0; }\n"
+ "} else { if (h < 12) { h += 12; }}",
s:"(AM|PM)"};
case "g":
case "G":
case "h":
case "H":
return {g:1,
c:"h = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{1,2})"};
case "i":
return {g:1,
c:"i = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{2})"};
case "s":
return {g:1,
c:"s = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{2})"};
case "O":
return {g:0,
c:null,
s:"[+-]\\d{4}"};
case "T":
return {g:0,
c:null,
s:"[A-Z]{3}"};
case "Z":
return {g:0,
c:null,
s:"[+-]\\d{1,5}"};
default:
return {g:0,
c:null,
s:String.escape(character)};
}
}
Date.prototype.getTimezone = function() {
return this.toString().replace(
/^.*? ([A-Z]{3}) [0-9]{4}.*$/, "$1").replace(
/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, "$1$2$3");
}
Date.prototype.getGMTOffset = function() {
return (this.getTimezoneOffset() > 0 ? "-" : "+")
+ String.leftPad(Math.floor(this.getTimezoneOffset() / 60), 2, "0")
+ String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
}
Date.prototype.getDayOfYear = function() {
var num = 0;
Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
for (var i = 0; i < this.getMonth(); ++i) {
num += Date.daysInMonth[i];
}
return num + this.getDate() - 1;
}
Date.prototype.getWeekOfYear = function() {
// Skip to Thursday of this week
var now = this.getDayOfYear() + (4 - this.getDay());
// Find the first Thursday of the year
var jan1 = new Date(this.getFullYear(), 0, 1);
var then = (7 - jan1.getDay() + 4);
document.write(then);
return String.leftPad(((now - then) / 7) + 1, 2, "0");
}
Date.prototype.isLeapYear = function() {
var year = this.getFullYear();
return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
}
Date.prototype.getFirstDayOfMonth = function() {
var day = (this.getDay() - (this.getDate() - 1)) % 7;
return (day < 0) ? (day + 7) : day;
}
Date.prototype.getLastDayOfMonth = function() {
var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
return (day < 0) ? (day + 7) : day;
}
Date.prototype.getDaysInMonth = function() {
Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
return Date.daysInMonth[this.getMonth()];
}
Date.prototype.getSuffix = function() {
switch (this.getDate()) {
case 1:
case 21:
case 31:
return "st";
case 2:
case 22:
return "nd";
case 3:
case 23:
return "rd";
default:
return "th";
}
}
String.escape = function(string) {
return string.replace(/('|\\)/g, "\\$1");
}
String.leftPad = function (val, size, ch) {
var result = new String(val);
if (ch == null) {
ch = " ";
}
while (result.length < size) {
result = ch + result;
}
return result;
}
Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
Date.monthNames =
["January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"];
Date.dayNames =
["Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"];
Date.y2kYear = 50;
Date.monthNumbers = {
Jan:0,
Feb:1,
Mar:2,
Apr:3,
May:4,
Jun:5,
Jul:6,
Aug:7,
Sep:8,
Oct:9,
Nov:10,
Dec:11};
Date.patterns = {
ISO8601LongPattern:"Y-m-d H:i:s",
ISO8601ShortPattern:"Y-m-d",
ShortDatePattern: "n/j/Y",
LongDatePattern: "l, F d, Y",
FullDateTimePattern: "l, F d, Y g:i:s A",
MonthDayPattern: "F d",
ShortTimePattern: "g:i A",
LongTimePattern: "g:i:s A",
SortableDateTimePattern: "Y-m-d\\TH:i:s",
UniversalSortableDateTimePattern: "Y-m-d H:i:sO",
YearMonthPattern: "F, Y"};
var date = new Date("1/1/2007 1:11:11");
for (i = 0; i < 4000; ++i) {
var shortFormat = date.dateFormat("Y-m-d");
var longFormat = date.dateFormat("l, F d, Y g:i:s A");
date.setTime(date.getTime() + 84266956);
}

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

@ -0,0 +1,95 @@
/*
* Copyright (C) Rich Moore. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/////. Start CORDIC
var AG_CONST = 0.6072529350;
function FIXED(X)
{
return X * 65536.0;
}
function FLOAT(X)
{
return X / 65536.0;
}
function DEG2RAD(X)
{
return 0.017453 * (X);
}
var Angles = [
FIXED(45.0), FIXED(26.565), FIXED(14.0362), FIXED(7.12502),
FIXED(3.57633), FIXED(1.78991), FIXED(0.895174), FIXED(0.447614),
FIXED(0.223811), FIXED(0.111906), FIXED(0.055953),
FIXED(0.027977)
];
function cordicsincos() {
var X;
var Y;
var TargetAngle;
var CurrAngle;
var Step;
X = FIXED(AG_CONST); /* AG_CONST * cos(0) */
Y = 0; /* AG_CONST * sin(0) */
TargetAngle = FIXED(28.027);
CurrAngle = 0;
for (Step = 0; Step < 12; Step++) {
var NewX;
if (TargetAngle > CurrAngle) {
NewX = X - (Y >> Step);
Y = (X >> Step) + Y;
X = NewX;
CurrAngle += Angles[Step];
} else {
NewX = X + (Y >> Step);
Y = -(X >> Step) + Y;
X = NewX;
CurrAngle -= Angles[Step];
}
}
}
///// End CORDIC
function cordic( runs ) {
var start = new Date();
for ( var i = 0 ; i < runs ; i++ ) {
cordicsincos();
}
var end = new Date();
return end.getTime() - start.getTime();
}
cordic(25000);

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

@ -0,0 +1,33 @@
// The Computer Language Shootout
// http://shootout.alioth.debian.org/
// contributed by Isaac Gouy
function partial(n){
var a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = a9 = 0.0;
var twothirds = 2.0/3.0;
var alt = -1.0;
var k2 = k3 = sk = ck = 0.0;
for (var k = 1; k <= n; k++){
k2 = k*k;
k3 = k2*k;
sk = Math.sin(k);
ck = Math.cos(k);
alt = -alt;
a1 += Math.pow(twothirds,k-1);
a2 += Math.pow(k,-0.5);
a3 += 1.0/(k*(k+1.0));
a4 += 1.0/(k3 * sk*sk);
a5 += 1.0/(k3 * ck*ck);
a6 += 1.0/k;
a7 += 1.0/k2;
a8 += alt/k;
a9 += alt/(2*k -1);
}
}
for (var i = 1024; i <= 16384; i *= 2) {
partial(i);
}

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

@ -0,0 +1,51 @@
// The Great Computer Language Shootout
// http://shootout.alioth.debian.org/
//
// contributed by Ian Osgood
function A(i,j) {
return 1/((i+j)*(i+j+1)/2+i+1);
}
function Au(u,v) {
for (var i=0; i<u.length; ++i) {
var t = 0;
for (var j=0; j<u.length; ++j)
t += A(i,j) * u[j];
v[i] = t;
}
}
function Atu(u,v) {
for (var i=0; i<u.length; ++i) {
var t = 0;
for (var j=0; j<u.length; ++j)
t += A(j,i) * u[j];
v[i] = t;
}
}
function AtAu(u,v,w) {
Au(u,w);
Atu(w,v);
}
function spectralnorm(n) {
var i, u=[], v=[], w=[], vv=0, vBv=0;
for (i=0; i<n; ++i) {
u[i] = 1; v[i] = w[i] = 0;
}
for (i=0; i<10; ++i) {
AtAu(u,v,w);
AtAu(v,u,w);
}
for (i=0; i<n; ++i) {
vBv += u[i]*v[i];
vv += v[i]*v[i];
}
return Math.sqrt(vBv/vv);
}
for (var i = 6; i <= 48; i *= 2) {
spectralnorm(i);
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -0,0 +1,135 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla XML-RPC Client component.
*
* The Initial Developer of the Original Code is
* Digital Creations 2, Inc.
* Portions created by the Initial Developer are Copyright (C) 2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Martijn Pieters <mj@digicool.com> (original author)
* Samuel Sieb <samuel@sieb.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// From: http://lxr.mozilla.org/mozilla/source/extensions/xml-rpc/src/nsXmlRpcClient.js#956
/* Convert data (an array of integers) to a Base64 string. */
var toBase64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var base64Pad = '=';
function toBase64(data) {
var result = '';
var length = data.length;
var i;
// Convert every three bytes to 4 ascii characters.
for (i = 0; i < (length - 2); i += 3) {
result += toBase64Table[data.charCodeAt(i) >> 2];
result += toBase64Table[((data.charCodeAt(i) & 0x03) << 4) + (data.charCodeAt(i+1) >> 4)];
result += toBase64Table[((data.charCodeAt(i+1) & 0x0f) << 2) + (data.charCodeAt(i+2) >> 6)];
result += toBase64Table[data.charCodeAt(i+2) & 0x3f];
}
// Convert the remaining 1 or 2 bytes, pad out to 4 characters.
if (length%3) {
i = length - (length%3);
result += toBase64Table[data.charCodeAt(i) >> 2];
if ((length%3) == 2) {
result += toBase64Table[((data.charCodeAt(i) & 0x03) << 4) + (data.charCodeAt(i+1) >> 4)];
result += toBase64Table[(data.charCodeAt(i+1) & 0x0f) << 2];
result += base64Pad;
} else {
result += toBase64Table[(data.charCodeAt(i) & 0x03) << 4];
result += base64Pad + base64Pad;
}
}
return result;
}
/* Convert Base64 data to a string */
var toBinaryTable = [
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
];
function base64ToString(data) {
var result = '';
var leftbits = 0; // number of bits decoded, but yet to be appended
var leftdata = 0; // bits decoded, but yet to be appended
// Convert one by one.
for (var i = 0; i < data.length; i++) {
var c = toBinaryTable[data.charCodeAt(i) & 0x7f];
var padding = (data.charCodeAt(i) == base64Pad.charCodeAt(0));
// Skip illegal characters and whitespace
if (c == -1) continue;
// Collect data into leftdata, update bitcount
leftdata = (leftdata << 6) | c;
leftbits += 6;
// If we have 8 or more bits, append 8 bits to the result
if (leftbits >= 8) {
leftbits -= 8;
// Append if not padding.
if (!padding)
result += String.fromCharCode((leftdata >> leftbits) & 0xff);
leftdata &= (1 << leftbits) - 1;
}
}
// If there are any bits left, the base64 string was corrupted
if (leftbits)
throw Components.Exception('Corrupted base64 string');
return result;
}
var str = "";
for ( var i = 0; i < 8192; i++ )
str += String.fromCharCode( (25 * Math.random()) + 97 );
for ( var i = 8192; i <= 16384; i *= 2 ) {
var base64;
base64 = toBase64(str);
base64ToString(base64);
// Double the string
str += str;
}
toBinaryTable = null;

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

@ -0,0 +1,85 @@
// The Great Computer Language Shootout
// http://shootout.alioth.debian.org
//
// Contributed by Ian Osgood
var last = 42, A = 3877, C = 29573, M = 139968;
function rand(max) {
last = (last * A + C) % M;
return max * last / M;
}
var ALU =
"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" +
"GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA" +
"CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT" +
"ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" +
"GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" +
"AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" +
"AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
var IUB = {
a:0.27, c:0.12, g:0.12, t:0.27,
B:0.02, D:0.02, H:0.02, K:0.02,
M:0.02, N:0.02, R:0.02, S:0.02,
V:0.02, W:0.02, Y:0.02
}
var HomoSap = {
a: 0.3029549426680,
c: 0.1979883004921,
g: 0.1975473066391,
t: 0.3015094502008
}
function makeCumulative(table) {
var last = null;
for (var c in table) {
if (last) table[c] += table[last];
last = c;
}
}
function fastaRepeat(n, seq) {
var seqi = 0, lenOut = 60;
while (n>0) {
if (n<lenOut) lenOut = n;
if (seqi + lenOut < seq.length) {
ret = seq.substring(seqi, seqi+lenOut);
seqi += lenOut;
} else {
var s = seq.substring(seqi);
seqi = lenOut - s.length;
ret = s + seq.substring(0, seqi);
}
n -= lenOut;
}
}
function fastaRandom(n, table) {
var line = new Array(60);
makeCumulative(table);
while (n>0) {
if (n<line.length) line = new Array(n);
for (var i=0; i<line.length; i++) {
var r = rand(1);
for (var c in table) {
if (r < table[c]) {
line[i] = c;
break;
}
}
}
ret = line.join('');
n -= line.length;
}
}
var ret;
var count = 7;
ret = fastaRepeat(2*count*100000, ALU);
ret = fastaRandom(3*count*1000, IUB);
ret = fastaRandom(5*count*1000, HomoSap);

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -0,0 +1,89 @@
letters = new Array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
numbers = new Array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26);
colors = new Array("FF","CC","99","66","33","00");
var endResult;
function doTest()
{
endResult = "";
// make up email address
for (var k=0;k<4000;k++)
{
name = makeName(6);
(k%2)?email=name+"@mac.com":email=name+"(at)mac.com";
// validate the email address
var pattern = /^[a-zA-Z0-9\-\._]+@[a-zA-Z0-9\-_]+(\.?[a-zA-Z0-9\-_]*)\.[a-zA-Z]{2,3}$/;
if(pattern.test(email))
{
var r = email + " appears to be a valid email address.";
addResult(r);
}
else
{
r = email + " does NOT appear to be a valid email address.";
addResult(r);
}
}
// make up ZIP codes
for (var s=0;s<4000;s++)
{
var zipGood = true;
var zip = makeNumber(4);
(s%2)?zip=zip+"xyz":zip=zip.concat("7");
// validate the zip code
for (var i = 0; i < zip.length; i++) {
var ch = zip.charAt(i);
if (ch < "0" || ch > "9") {
zipGood = false;
r = zip + " contains letters.";
addResult(r);
}
}
if (zipGood && zip.length>5)
{
zipGood = false;
r = zip + " is longer than five characters.";
addResult(r);
}
if (zipGood)
{
r = zip + " appears to be a valid ZIP code.";
addResult(r);
}
}
}
function makeName(n)
{
var tmp = "";
for (var i=0;i<n;i++)
{
var l = Math.floor(26*Math.random());
tmp += letters[l];
}
return tmp;
}
function makeNumber(n)
{
var tmp = "";
for (var i=0;i<n;i++)
{
var l = Math.floor(9*Math.random());
tmp = tmp.concat(l);
}
return tmp;
}
function addResult(r)
{
endResult += "\n" + r;
}
doTest();

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

@ -0,0 +1,71 @@
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function(){
const testNames = [
"3d-cube",
"3d-morph",
"3d-raytrace",
"access-binary-trees",
"access-fannkuch",
"access-nbody",
"access-nsieve",
"bitops-3bit-bits-in-byte",
"bitops-bits-in-byte",
"bitops-bitwise-and",
"bitops-nsieve-bits",
"controlflow-recursive",
"crypto-aes",
"crypto-md5",
"crypto-sha1",
"date-format-tofte",
"date-format-xparb",
"math-cordic",
"math-partial-sums",
"math-spectral-norm",
"regexp-dna",
"string-base64",
"string-fasta",
"string-tagcloud",
"string-unpack-code",
"string-validate-input"
];
for (let testName of testNames) {
let testScript = testName + ".js";
let startTime = new Date;
if (testScript.indexOf('parse-only') >= 0)
checkSyntax(testScript);
else
load(testScript);
let duration = new Date() - startTime;
gc();
print(testName+":", duration);
}
})();

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

@ -7220,6 +7220,37 @@
],
"description": "Number of 'event' pings sent, by reason"
},
"TELEMETRY_EVENT_REGISTRATION_ERROR": {
"record_in_processes": ["main"],
"alert_emails": ["telemetry-client-dev@mozilla.com", "chutten@mozilla.com"],
"bug_numbers": [1480204],
"expires_in_version": "never",
"kind": "categorical",
"labels": [
"Other",
"Name",
"Category",
"Method",
"Object",
"ExtraKeys"
],
"description": "Number of event registration failures, by field causing the failure"
},
"TELEMETRY_EVENT_RECORDING_ERROR": {
"record_in_processes": ["all"],
"alert_emails": ["telemetry-client-dev@mozilla.com", "chutten@mozilla.com"],
"bug_numbers": [1480204],
"expires_in_version": "never",
"kind": "categorical",
"labels": [
"UnknownEvent",
"Expired",
"ExtraKey",
"Value",
"Extra"
],
"description": "Number of event recording failures, by type of failure"
},
"TELEMETRY_TEST_FLAG": {
"record_in_processes": ["main", "content"],
"alert_emails": ["telemetry-client-dev@mozilla.com"],
@ -9208,7 +9239,7 @@
"MEDIA_RECORDER_RECORDING_DURATION": {
"record_in_processes": ["main", "content"],
"alert_emails": ["bvandyk@mozilla.com"],
"expires_in_version": "64",
"expires_in_version": "68",
"kind": "exponential",
"high": 3600,
"n_buckets": 100,
@ -9218,7 +9249,7 @@
"MEDIA_RECORDER_TRACK_ENCODER_INIT_TIMEOUT_TYPE": {
"record_in_processes": ["main", "content"],
"alert_emails": ["bvandyk@mozilla.com"],
"expires_in_version": "64",
"expires_in_version": "68",
"kind": "enumerated",
"n_values": 4,
"bug_numbers": [1400757],

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

@ -769,7 +769,7 @@ mediarecorder:
- 1400757
description: >
The number of times a MediaRecorder has been started. Recorded when a MediaRecorder starts
expires: "64"
expires: "68"
kind: uint
notification_emails:
- bvandyk@mozilla.com

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

@ -25,6 +25,7 @@
#include "nsUTF8Utils.h"
#include "nsPrintfCString.h"
#include "Telemetry.h"
#include "TelemetryCommon.h"
#include "TelemetryEvent.h"
#include "TelemetryEventData.h"
@ -38,6 +39,8 @@ using mozilla::Maybe;
using mozilla::Nothing;
using mozilla::StaticAutoPtr;
using mozilla::TimeStamp;
using mozilla::Telemetry::LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR;
using mozilla::Telemetry::LABELS_TELEMETRY_EVENT_RECORDING_ERROR;
using mozilla::Telemetry::Common::AutoHashtable;
using mozilla::Telemetry::Common::IsExpiredVersion;
using mozilla::Telemetry::Common::CanRecordDataset;
@ -455,6 +458,7 @@ RecordEvent(const StaticMutexAutoLock& lock, ProcessID processType,
// Look up the event id.
EventKey* eventKey = GetEventKey(lock, category, method, object);
if (!eventKey) {
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_RECORDING_ERROR::UnknownEvent);
return RecordEventResult::UnknownEvent;
}
@ -463,6 +467,7 @@ RecordEvent(const StaticMutexAutoLock& lock, ProcessID processType,
// have to be removed at a specific time or version.
// Even logging warnings would become very noisy.
if (IsExpired(*eventKey)) {
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_RECORDING_ERROR::Expired);
return RecordEventResult::ExpiredEvent;
}
@ -475,6 +480,7 @@ RecordEvent(const StaticMutexAutoLock& lock, ProcessID processType,
// Check whether the extra keys passed are valid.
if (!CheckExtraKeysValid(*eventKey, extra)) {
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_RECORDING_ERROR::ExtraKey);
return RecordEventResult::InvalidExtraKey;
}
@ -804,6 +810,7 @@ TelemetryEvent::RecordEvent(const nsACString& aCategory, const nsACString& aMeth
if ((optional_argc > 0) && !aValue.isNull() && !aValue.isString()) {
LogToBrowserConsole(nsIScriptError::warningFlag,
NS_LITERAL_STRING("Invalid type for value parameter."));
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_RECORDING_ERROR::Value);
return NS_OK;
}
@ -814,6 +821,7 @@ TelemetryEvent::RecordEvent(const nsACString& aCategory, const nsACString& aMeth
if (!jsStr.init(cx, aValue)) {
LogToBrowserConsole(nsIScriptError::warningFlag,
NS_LITERAL_STRING("Invalid string value for value parameter."));
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_RECORDING_ERROR::Value);
return NS_OK;
}
@ -830,6 +838,7 @@ TelemetryEvent::RecordEvent(const nsACString& aCategory, const nsACString& aMeth
if ((optional_argc > 1) && !aExtra.isNull() && !aExtra.isObject()) {
LogToBrowserConsole(nsIScriptError::warningFlag,
NS_LITERAL_STRING("Invalid type for extra parameter."));
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_RECORDING_ERROR::Extra);
return NS_OK;
}
@ -841,6 +850,7 @@ TelemetryEvent::RecordEvent(const nsACString& aCategory, const nsACString& aMeth
if (!JS_Enumerate(cx, obj, &ids)) {
LogToBrowserConsole(nsIScriptError::warningFlag,
NS_LITERAL_STRING("Failed to enumerate object."));
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_RECORDING_ERROR::Extra);
return NS_OK;
}
@ -849,6 +859,7 @@ TelemetryEvent::RecordEvent(const nsACString& aCategory, const nsACString& aMeth
if (!key.init(cx, ids[i])) {
LogToBrowserConsole(nsIScriptError::warningFlag,
NS_LITERAL_STRING("Extra dictionary should only contain string keys."));
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_RECORDING_ERROR::Extra);
return NS_OK;
}
@ -856,6 +867,7 @@ TelemetryEvent::RecordEvent(const nsACString& aCategory, const nsACString& aMeth
if (!JS_GetPropertyById(cx, obj, ids[i], &value)) {
LogToBrowserConsole(nsIScriptError::warningFlag,
NS_LITERAL_STRING("Failed to get extra property."));
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_RECORDING_ERROR::Extra);
return NS_OK;
}
@ -863,6 +875,7 @@ TelemetryEvent::RecordEvent(const nsACString& aCategory, const nsACString& aMeth
if (!value.isString() || !jsStr.init(cx, value)) {
LogToBrowserConsole(nsIScriptError::warningFlag,
NS_LITERAL_STRING("Extra properties should have string values."));
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_RECORDING_ERROR::Extra);
return NS_OK;
}
@ -993,17 +1006,20 @@ TelemetryEvent::RegisterEvents(const nsACString& aCategory,
if (!IsValidIdentifierString(aCategory, 30, true, true)) {
JS_ReportErrorASCII(cx, "Category parameter should match the identifier pattern.");
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Category);
return NS_ERROR_INVALID_ARG;
}
if (!aEventData.isObject()) {
JS_ReportErrorASCII(cx, "Event data parameter should be an object");
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Other);
return NS_ERROR_INVALID_ARG;
}
JS::RootedObject obj(cx, &aEventData.toObject());
JS::Rooted<JS::IdVector> eventPropertyIds(cx, JS::IdVector(cx));
if (!JS_Enumerate(cx, obj, &eventPropertyIds)) {
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Other);
return NS_ERROR_FAILURE;
}
@ -1015,16 +1031,19 @@ TelemetryEvent::RegisterEvents(const nsACString& aCategory,
for (size_t i = 0, n = eventPropertyIds.length(); i < n; i++) {
nsAutoJSString eventName;
if (!eventName.init(cx, eventPropertyIds[i])) {
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Other);
return NS_ERROR_FAILURE;
}
if (!IsValidIdentifierString(NS_ConvertUTF16toUTF8(eventName), kMaxMethodNameByteLength, false, true)) {
JS_ReportErrorASCII(cx, "Event names should match the identifier pattern.");
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Name);
return NS_ERROR_INVALID_ARG;
}
JS::RootedValue value(cx);
if (!JS_GetPropertyById(cx, obj, eventPropertyIds[i], &value) || !value.isObject()) {
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Other);
return NS_ERROR_FAILURE;
}
JS::RootedObject eventObj(cx, &value.toObject());
@ -1038,10 +1057,12 @@ TelemetryEvent::RegisterEvents(const nsACString& aCategory,
// The methods & objects properties are required.
if (!GetArrayPropertyValues(cx, eventObj, "methods", &methods)) {
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Other);
return NS_ERROR_FAILURE;
}
if (!GetArrayPropertyValues(cx, eventObj, "objects", &objects)) {
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Other);
return NS_ERROR_FAILURE;
}
@ -1049,6 +1070,7 @@ TelemetryEvent::RegisterEvents(const nsACString& aCategory,
bool hasProperty = false;
if (JS_HasProperty(cx, eventObj, "extra_keys", &hasProperty) && hasProperty) {
if (!GetArrayPropertyValues(cx, eventObj, "extra_keys", &extra_keys)) {
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Other);
return NS_ERROR_FAILURE;
}
}
@ -1057,6 +1079,7 @@ TelemetryEvent::RegisterEvents(const nsACString& aCategory,
if (JS_HasProperty(cx, eventObj, "expired", &hasProperty) && hasProperty) {
JS::RootedValue temp(cx);
if (!JS_GetProperty(cx, eventObj, "expired", &temp) || !temp.isBoolean()) {
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Other);
return NS_ERROR_FAILURE;
}
@ -1067,6 +1090,7 @@ TelemetryEvent::RegisterEvents(const nsACString& aCategory,
if (JS_HasProperty(cx, eventObj, "record_on_release", &hasProperty) && hasProperty) {
JS::RootedValue temp(cx);
if (!JS_GetProperty(cx, eventObj, "record_on_release", &temp) || !temp.isBoolean()) {
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Other);
return NS_ERROR_FAILURE;
}
@ -1077,6 +1101,7 @@ TelemetryEvent::RegisterEvents(const nsACString& aCategory,
for (auto& method : methods) {
if (!IsValidIdentifierString(method, kMaxMethodNameByteLength, false, true)) {
JS_ReportErrorASCII(cx, "Method names should match the identifier pattern.");
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Method);
return NS_ERROR_INVALID_ARG;
}
}
@ -1085,6 +1110,7 @@ TelemetryEvent::RegisterEvents(const nsACString& aCategory,
for (auto& object : objects) {
if (!IsValidIdentifierString(object, kMaxObjectNameByteLength, false, true)) {
JS_ReportErrorASCII(cx, "Object names should match the identifier pattern.");
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::Object);
return NS_ERROR_INVALID_ARG;
}
}
@ -1092,11 +1118,13 @@ TelemetryEvent::RegisterEvents(const nsACString& aCategory,
// Validate extra keys.
if (extra_keys.Length() > kMaxExtraKeyCount) {
JS_ReportErrorASCII(cx, "No more than 10 extra keys can be registered.");
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::ExtraKeys);
return NS_ERROR_INVALID_ARG;
}
for (auto& key : extra_keys) {
if (!IsValidIdentifierString(key, kMaxExtraKeyNameByteLength, false, true)) {
JS_ReportErrorASCII(cx, "Extra key names should match the identifier pattern.");
mozilla::Telemetry::AccumulateCategorical(LABELS_TELEMETRY_EVENT_REGISTRATION_ERROR::ExtraKeys);
return NS_ERROR_INVALID_ARG;
}
}

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

@ -45,7 +45,7 @@ function checkEventFormat(events) {
*/
function checkEventSummary(summaries, clearScalars) {
let scalars = Telemetry.snapshotKeyedScalars(OPTOUT, clearScalars);
dump(JSON.stringify(summaries));
for (let [process, [category, eObject, method], count] of summaries) {
let uniqueEventName = `${category}#${eObject}#${method}`;
let summaryCount;
@ -58,6 +58,30 @@ function checkEventSummary(summaries, clearScalars) {
}
}
function checkRegistrationFailure(failureType) {
let snapshot = Telemetry.snapshotHistograms(OPTIN, true);
Assert.ok("parent" in snapshot,
"There should be at least one parent histogram when checking for registration failures.");
Assert.ok("TELEMETRY_EVENT_REGISTRATION_ERROR" in snapshot.parent,
"TELEMETRY_EVENT_REGISTRATION_ERROR should exist when checking for registration failures.");
let counts = snapshot.parent.TELEMETRY_EVENT_REGISTRATION_ERROR.counts;
Assert.ok(!!counts,
"TELEMETRY_EVENT_REGISTRATION_ERROR's counts should exist when checking for registration failures.");
Assert.equal(counts[failureType], 1, `Event registration ought to have failed due to type ${failureType}`);
}
function checkRecordingFailure(failureType) {
let snapshot = Telemetry.snapshotHistograms(OPTIN, true);
Assert.ok("parent" in snapshot,
"There should be at least one parent histogram when checking for recording failures.");
Assert.ok("TELEMETRY_EVENT_RECORDING_ERROR" in snapshot.parent,
"TELEMETRY_EVENT_RECORDING_ERROR should exist when checking for recording failures.");
let counts = snapshot.parent.TELEMETRY_EVENT_RECORDING_ERROR.counts;
Assert.ok(!!counts,
"TELEMETRY_EVENT_RECORDING_ERROR's counts should exist when checking for recording failures.");
Assert.equal(counts[failureType], 1, `Event recording ought to have failed due to type ${failureType}`);
}
add_task(async function test_event_summary_limit() {
if (AppConstants.DEBUG) {
// This test will intentionally assert in DEBUG builds
@ -198,12 +222,15 @@ add_task(async function test_recording() {
Assert.throws(() => Telemetry.recordEvent("unknown.category", "test1", "object1"),
/Error: Unknown event: \["unknown.category", "test1", "object1"\]/,
"Should throw on unknown category.");
checkRecordingFailure(0 /* UnknownEvent */);
Assert.throws(() => Telemetry.recordEvent("telemetry.test", "unknown", "object1"),
/Error: Unknown event: \["telemetry.test", "unknown", "object1"\]/,
"Should throw on unknown method.");
checkRecordingFailure(0 /* UnknownEvent */);
Assert.throws(() => Telemetry.recordEvent("telemetry.test", "test1", "unknown"),
/Error: Unknown event: \["telemetry.test", "test1", "unknown"\]/,
"Should throw on unknown object.");
checkRecordingFailure(0 /* UnknownEvent */);
let checkEvents = (events, expectedEvents) => {
checkEventFormat(events);
@ -280,6 +307,7 @@ add_task(async function test_expiry() {
// Recording call with event that is expired by version.
Telemetry.recordEvent("telemetry.test", "expired_version", "object1");
checkRecordingFailure(1 /* Expired */);
let snapshot = Telemetry.snapshotEvents(OPTIN, true);
Assert.equal(Object.keys(snapshot).length, 0, "Should not record event with expired version.");
@ -297,21 +325,25 @@ add_task(async function test_invalidParams() {
Telemetry.recordEvent("telemetry.test", "test1", "object1", 1);
let snapshot = Telemetry.snapshotEvents(OPTIN, true);
Assert.equal(Object.keys(snapshot).length, 0, "Should not record event when value argument with invalid type is passed.");
checkRecordingFailure(3 /* Value */);
// Recording call with wrong type for extra argument.
Telemetry.recordEvent("telemetry.test", "test1", "object1", null, "invalid");
snapshot = Telemetry.snapshotEvents(OPTIN, true);
Assert.equal(Object.keys(snapshot).length, 0, "Should not record event when extra argument with invalid type is passed.");
checkRecordingFailure(4 /* Extra */);
// Recording call with unknown extra key.
Telemetry.recordEvent("telemetry.test", "test1", "object1", null, {"key3": "x"});
snapshot = Telemetry.snapshotEvents(OPTIN, true);
Assert.equal(Object.keys(snapshot).length, 0, "Should not record event when extra argument with invalid key is passed.");
checkRecordingFailure(2 /* ExtraKey */);
// Recording call with invalid value type.
Telemetry.recordEvent("telemetry.test", "test1", "object1", null, {"key3": 1});
snapshot = Telemetry.snapshotEvents(OPTIN, true);
Assert.equal(Object.keys(snapshot).length, 0, "Should not record event when extra argument with invalid value type is passed.");
checkRecordingFailure(4 /* Extra */);
});
add_task(async function test_storageLimit() {
@ -445,6 +477,7 @@ add_task(async function test_dynamicEvents() {
Assert.throws(() => Telemetry.recordEvent("telemetry.test.dynamic", "unknown", "unknown"),
/Error: Unknown event: \["telemetry\.test\.dynamic", "unknown", "unknown"\]/,
"Should throw when recording an unknown dynamic event.");
checkRecordingFailure(0 /* UnknownEvent */);
// Now check that the snapshot contains the expected data.
let snapshot = Telemetry.snapshotEvents(OPTIN, false);
@ -507,6 +540,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
Telemetry.clearEvents();
// Test registration of invalid categories.
Telemetry.snapshotHistograms(OPTIN, true); // Clear histograms before we begin.
Assert.throws(() => Telemetry.registerEvents("telemetry+test+dynamic", {
"test1": {
methods: ["test1"],
@ -515,6 +549,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
}),
/Category parameter should match the identifier pattern\./,
"Should throw when registering category names with invalid characters.");
checkRegistrationFailure(2 /* Category */);
Assert.throws(() => Telemetry.registerEvents("telemetry.test.test.test.test.test.test.test.test", {
"test1": {
methods: ["test1"],
@ -523,6 +558,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
}),
/Category parameter should match the identifier pattern\./,
"Should throw when registering overly long category names.");
checkRegistrationFailure(2 /* Category */);
// Test registration of invalid event names.
Assert.throws(() => Telemetry.registerEvents("telemetry.test.dynamic1", {
@ -533,6 +569,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
}),
/Event names should match the identifier pattern\./,
"Should throw when registering event names with invalid characters.");
checkRegistrationFailure(1 /* Name */);
Assert.throws(() => Telemetry.registerEvents("telemetry.test.dynamic2", {
"test1test1test1test1test1test1test1": {
methods: ["test1"],
@ -541,6 +578,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
}),
/Event names should match the identifier pattern\./,
"Should throw when registering overly long event names.");
checkRegistrationFailure(1 /* Name */);
// Test registration of invalid method names.
Assert.throws(() => Telemetry.registerEvents("telemetry.test.dynamic3", {
@ -551,6 +589,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
}),
/Method names should match the identifier pattern\./,
"Should throw when registering method names with invalid characters.");
checkRegistrationFailure(3 /* Method */);
Assert.throws(() => Telemetry.registerEvents("telemetry.test.dynamic", {
"test1": {
methods: ["test1test1test1test1test1test1test1"],
@ -559,6 +598,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
}),
/Method names should match the identifier pattern\./,
"Should throw when registering overly long method names.");
checkRegistrationFailure(3 /* Method */);
// Test registration of invalid object names.
Assert.throws(() => Telemetry.registerEvents("telemetry.test.dynamic4", {
@ -569,6 +609,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
}),
/Object names should match the identifier pattern\./,
"Should throw when registering object names with invalid characters.");
checkRegistrationFailure(4 /* Object */);
Assert.throws(() => Telemetry.registerEvents("telemetry.test.dynamic5", {
"test1": {
methods: ["test1"],
@ -577,6 +618,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
}),
/Object names should match the identifier pattern\./,
"Should throw when registering overly long object names.");
checkRegistrationFailure(4 /* Object */);
// Test validation of invalid key names.
Assert.throws(() => Telemetry.registerEvents("telemetry.test.dynamic6", {
@ -588,6 +630,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
}),
/Extra key names should match the identifier pattern\./,
"Should throw when registering extra key names with invalid characters.");
checkRegistrationFailure(5 /* ExtraKeys */);
// Test validation of key names that are too long - we allow a maximum of 15 characters.
Assert.throws(() => Telemetry.registerEvents("telemetry.test.dynamic7", {
@ -599,6 +642,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
}),
/Extra key names should match the identifier pattern\./,
"Should throw when registering extra key names which are too long.");
checkRegistrationFailure(5 /* ExtraKeys */);
Telemetry.registerEvents("telemetry.test.dynamic8", {
"test1": {
methods: ["test1"],
@ -617,6 +661,7 @@ add_task(async function test_dynamicEventRegistrationValidation() {
}),
/No more than 10 extra keys can be registered\./,
"Should throw when registering too many extra keys.");
checkRegistrationFailure(5 /* ExtraKeys */);
Telemetry.registerEvents("telemetry.test.dynamic10", {
"test1": {
methods: ["test1"],

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

@ -34,7 +34,9 @@ def normalize_osx_path(p):
return p
def is_l10n_file(path):
return '/locale/' in path or '/localization/' in path
return ('/locale/' in path or
'/localization/' in path or
path.startswith('localization/'))
def normalize_path(p):
return normalize_osx_path(p)

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