mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Merge mozilla-central to fx-team
This commit is contained in:
commit
3db7c01bb7
@ -7,7 +7,6 @@ obj*/**
|
||||
# We ignore all these directories by default, until we get them enabled.
|
||||
# If you are enabling a directory, please add directory specific exclusions
|
||||
# below.
|
||||
accessible/**
|
||||
addon-sdk/**
|
||||
build/**
|
||||
caps/**
|
||||
|
15
accessible/.eslintrc
Normal file
15
accessible/.eslintrc
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": [
|
||||
"../.eslintrc"
|
||||
],
|
||||
"globals": {
|
||||
"Cc": true,
|
||||
"Ci": true,
|
||||
"Components": true,
|
||||
"console": true,
|
||||
"Cu": true,
|
||||
"dump": true,
|
||||
"Services": true,
|
||||
"XPCOMUtils": true
|
||||
}
|
||||
}
|
@ -78,7 +78,7 @@ TextAttrsMgr::GetAttributes(nsIPersistentProperties* aAttributes,
|
||||
return; // XXX: we don't support text attrs on document with no body
|
||||
|
||||
nsIFrame* rootFrame = mHyperTextAcc->GetFrame();
|
||||
NS_ASSERTION(rootFrame, "No frame for accessible!");
|
||||
MOZ_ASSERT(rootFrame, "No frame for accessible!");
|
||||
if (!rootFrame)
|
||||
return;
|
||||
|
||||
@ -87,9 +87,10 @@ TextAttrsMgr::GetAttributes(nsIPersistentProperties* aAttributes,
|
||||
if (mOffsetAcc) {
|
||||
offsetNode = mOffsetAcc->GetContent();
|
||||
offsetElm = nsCoreUtils::GetDOMElementFor(offsetNode);
|
||||
NS_ASSERTION(offsetElm, "No element for offset accessible!");
|
||||
MOZ_ASSERT(offsetElm, "No element for offset accessible!");
|
||||
if (!offsetElm)
|
||||
return;
|
||||
|
||||
frame = offsetElm->GetPrimaryFrame();
|
||||
}
|
||||
|
||||
@ -165,6 +166,9 @@ TextAttrsMgr::GetRange(TextAttr* aAttrArray[], uint32_t aAttrArrayLen,
|
||||
if (!currAcc->IsText())
|
||||
break;
|
||||
|
||||
MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc->GetContent()),
|
||||
"Text accessible has to have an associated DOM element");
|
||||
|
||||
bool offsetFound = false;
|
||||
for (uint32_t attrIdx = 0; attrIdx < aAttrArrayLen; attrIdx++) {
|
||||
TextAttr* textAttr = aAttrArray[attrIdx];
|
||||
@ -187,6 +191,9 @@ TextAttrsMgr::GetRange(TextAttr* aAttrArray[], uint32_t aAttrArrayLen,
|
||||
if (!currAcc->IsText())
|
||||
break;
|
||||
|
||||
MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc->GetContent()),
|
||||
"Text accessible has to have an associated DOM element");
|
||||
|
||||
bool offsetFound = false;
|
||||
for (uint32_t attrIdx = 0; attrIdx < aAttrArrayLen; attrIdx++) {
|
||||
TextAttr* textAttr = aAttrArray[attrIdx];
|
||||
@ -344,8 +351,13 @@ TextAttrsMgr::BGColorTextAttr::
|
||||
GetValueFor(Accessible* aAccessible, nscolor* aValue)
|
||||
{
|
||||
nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
return frame ? GetColor(frame, aValue) : false;
|
||||
if (elm) {
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
return GetColor(frame, aValue);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -407,12 +419,13 @@ TextAttrsMgr::ColorTextAttr::
|
||||
GetValueFor(Accessible* aAccessible, nscolor* aValue)
|
||||
{
|
||||
nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = frame->StyleColor()->mColor;
|
||||
return true;
|
||||
if (elm) {
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = frame->StyleColor()->mColor;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -445,8 +458,13 @@ TextAttrsMgr::FontFamilyTextAttr::
|
||||
GetValueFor(Accessible* aAccessible, nsString* aValue)
|
||||
{
|
||||
nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
return frame ? GetFontFamily(frame, *aValue) : false;
|
||||
if (elm) {
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
return GetFontFamily(frame, *aValue);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -494,13 +512,14 @@ bool
|
||||
TextAttrsMgr::FontSizeTextAttr::
|
||||
GetValueFor(Accessible* aAccessible, nscoord* aValue)
|
||||
{
|
||||
nsIContent* content = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
|
||||
nsIFrame* frame = content->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = frame->StyleFont()->mSize;
|
||||
return true;
|
||||
nsIContent* el = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
|
||||
if (el) {
|
||||
nsIFrame* frame = el->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = frame->StyleFont()->mSize;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -551,12 +570,13 @@ TextAttrsMgr::FontStyleTextAttr::
|
||||
GetValueFor(Accessible* aAccessible, nscoord* aValue)
|
||||
{
|
||||
nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = frame->StyleFont()->mFont.style;
|
||||
return true;
|
||||
if (elm) {
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = frame->StyleFont()->mFont.style;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -593,12 +613,13 @@ TextAttrsMgr::FontWeightTextAttr::
|
||||
GetValueFor(Accessible* aAccessible, int32_t* aValue)
|
||||
{
|
||||
nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = GetFontWeight(frame);
|
||||
return true;
|
||||
if (elm) {
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = GetFontWeight(frame);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -727,12 +748,13 @@ TextAttrsMgr::TextDecorTextAttr::
|
||||
GetValueFor(Accessible* aAccessible, TextDecorValue* aValue)
|
||||
{
|
||||
nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = TextDecorValue(frame);
|
||||
return aValue->IsDefined();
|
||||
if (elm) {
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = TextDecorValue(frame);
|
||||
return aValue->IsDefined();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -790,12 +812,13 @@ TextAttrsMgr::TextPosTextAttr::
|
||||
GetValueFor(Accessible* aAccessible, TextPosValue* aValue)
|
||||
{
|
||||
nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = GetTextPosValue(frame);
|
||||
return *aValue != eTextPosNone;
|
||||
if (elm) {
|
||||
nsIFrame* frame = elm->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
*aValue = GetTextPosValue(frame);
|
||||
return *aValue != eTextPosNone;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -276,10 +276,9 @@ var OutputGenerator = {
|
||||
_addMencloseNotations: function _addMencloseNotations(aOutput, aAccessible) {
|
||||
let notations = Utils.getAttributes(aAccessible).notation || 'longdiv';
|
||||
aOutput[this.outputOrder === OUTPUT_DESC_FIRST ? 'push' : 'unshift'].apply(
|
||||
aOutput, [for (notation of notations.split(' '))
|
||||
{string: this._getOutputName('notation-' + notation)}
|
||||
]
|
||||
);
|
||||
aOutput, notations.split(' ').map(notation => {
|
||||
return { string: this._getOutputName('notation-' + notation) };
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -21,3 +21,5 @@ if CONFIG['MOZ_XUL']:
|
||||
DIRS += ['xul']
|
||||
|
||||
TEST_DIRS += ['tests/mochitest']
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
|
||||
|
202
accessible/tests/browser/.eslintrc
Normal file
202
accessible/tests/browser/.eslintrc
Normal file
@ -0,0 +1,202 @@
|
||||
{
|
||||
"extends": [
|
||||
"../../../testing/mochitest/browser.eslintrc"
|
||||
],
|
||||
// All globals made available in the test environment.
|
||||
"globals": {
|
||||
// Content scripts have global 'content' object
|
||||
"content": true,
|
||||
|
||||
// Defined in accessible/tests/mochitest/ common.js, name.js, states.js
|
||||
"prettyName": true,
|
||||
"statesToString": true,
|
||||
"eventTypeToString": true,
|
||||
"testName": true,
|
||||
"testStates": true,
|
||||
"testAccessibleTree": true,
|
||||
"isAccessible": true,
|
||||
"getAccessibleDOMNodeID": true,
|
||||
|
||||
// Defined for all accessibility browser tests.
|
||||
"addAccessibleTask": true,
|
||||
"BrowserTestUtils": true,
|
||||
"ContentTask": true,
|
||||
"gBrowser": true,
|
||||
"isDefunct": true,
|
||||
"loadScripts": true,
|
||||
"Logger": true,
|
||||
"MOCHITESTS_DIR": true,
|
||||
"waitForEvent": true,
|
||||
"waitForMultipleEvents": true,
|
||||
"invokeSetAttribute": true,
|
||||
"invokeSetStyle": true,
|
||||
"invokeFocus": true,
|
||||
"findAccessibleChildByID": true
|
||||
},
|
||||
"rules": {
|
||||
"mozilla/mark-test-function-used": 1,
|
||||
"mozilla/no-aArgs": 1,
|
||||
"mozilla/no-cpows-in-tests": 1,
|
||||
"mozilla/reject-importGlobalProperties": 1,
|
||||
"mozilla/var-only-at-top-level": 1,
|
||||
|
||||
"block-scoped-var": 2,
|
||||
"brace-style": [2, "1tbs"],
|
||||
"camelcase": 2,
|
||||
"comma-dangle": [2, "never"],
|
||||
"comma-spacing": 2,
|
||||
"comma-style": [2, "last"],
|
||||
"complexity": [2, 35],
|
||||
"consistent-this": 0,
|
||||
"curly": [2, "multi-line"],
|
||||
"default-case": 0,
|
||||
"dot-location": [2, "property"],
|
||||
"dot-notation": 2,
|
||||
"eol-last": 2,
|
||||
"eqeqeq": 0,
|
||||
"func-names": 0,
|
||||
"func-style": 0,
|
||||
"generator-star": 0,
|
||||
"global-strict": 0,
|
||||
"handle-callback-err": [2, "er"],
|
||||
"indent": [2, 2, {"SwitchCase": 1}],
|
||||
"key-spacing": [2, {"beforeColon": false, "afterColon": true}],
|
||||
"linebreak-style": 0,
|
||||
"max-depth": 0,
|
||||
"max-nested-callbacks": [2, 3],
|
||||
"max-params": 0,
|
||||
"max-statements": 0,
|
||||
"new-cap": [2, {"capIsNew": false}],
|
||||
"new-parens": 2,
|
||||
"no-array-constructor": 2,
|
||||
"no-bitwise": 0,
|
||||
"no-caller": 2,
|
||||
"no-catch-shadow": 2,
|
||||
"no-comma-dangle": 0,
|
||||
"no-cond-assign": 2,
|
||||
"no-console": 0,
|
||||
"no-constant-condition": 0,
|
||||
"no-continue": 0,
|
||||
"no-control-regex": 2,
|
||||
"no-debugger": 2,
|
||||
"no-delete-var": 2,
|
||||
"no-div-regex": 0,
|
||||
"no-dupe-args": 2,
|
||||
"no-dupe-keys": 2,
|
||||
"no-duplicate-case": 2,
|
||||
"no-else-return": 2,
|
||||
"no-empty": 2,
|
||||
"no-empty-character-class": 2,
|
||||
"no-eval": 2,
|
||||
"no-ex-assign": 2,
|
||||
"no-extend-native": 2,
|
||||
"no-extra-bind": 2,
|
||||
"no-extra-boolean-cast": 2,
|
||||
"no-extra-parens": 0,
|
||||
"no-extra-semi": 2,
|
||||
"no-extra-strict": 0,
|
||||
"no-fallthrough": 2,
|
||||
"no-floating-decimal": 0,
|
||||
"no-inline-comments": 0,
|
||||
"no-lonely-if": 2,
|
||||
"no-mixed-requires": 0,
|
||||
"no-mixed-spaces-and-tabs": 2,
|
||||
"no-multi-spaces": 2,
|
||||
"no-multi-str": 2,
|
||||
"no-multiple-empty-lines": [2, {"max": 1}],
|
||||
"no-native-reassign": 2,
|
||||
"no-nested-ternary": 2,
|
||||
"no-new-require": 0,
|
||||
"no-octal": 2,
|
||||
"no-param-reassign": 0,
|
||||
"no-path-concat": 0,
|
||||
"no-plusplus": 0,
|
||||
"no-process-env": 0,
|
||||
"no-process-exit": 0,
|
||||
"no-proto": 2,
|
||||
"no-redeclare": 2,
|
||||
"no-regex-spaces": 2,
|
||||
"no-reserved-keys": 0,
|
||||
"no-restricted-modules": 0,
|
||||
"no-return-assign": 1,
|
||||
"no-script-url": 0,
|
||||
"no-self-compare": 2,
|
||||
"no-sequences": 2,
|
||||
"no-shadow": 1,
|
||||
"no-shadow-restricted-names": 2,
|
||||
"no-space-before-semi": 0,
|
||||
"no-spaced-func": 2,
|
||||
"no-sparse-arrays": 2,
|
||||
"no-sync": 0,
|
||||
"no-ternary": 0,
|
||||
"no-throw-literal": 2,
|
||||
"no-trailing-spaces": 2,
|
||||
"no-undef": 2,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-undefined": 0,
|
||||
"no-unneeded-ternary": 2,
|
||||
"no-unreachable": 2,
|
||||
"no-unused-vars": [2, {"vars": "all", "args": "none"}],
|
||||
"no-use-before-define": 0,
|
||||
"no-var": 0,
|
||||
"no-warning-comments": 0,
|
||||
"no-with": 2,
|
||||
"object-shorthand": 0,
|
||||
"one-var": [2, "never"],
|
||||
"padded-blocks": [2, "never"],
|
||||
"quote-props": 0,
|
||||
"radix": 2,
|
||||
"semi": [2, "always"],
|
||||
"semi-spacing": [2, {"before": false, "after": true}],
|
||||
"sort-vars": 0,
|
||||
"space-after-function-name": 0,
|
||||
"keyword-spacing": 2,
|
||||
"space-before-blocks": 2,
|
||||
"space-before-function-parentheses": 0,
|
||||
"space-before-function-paren": [2, "never"],
|
||||
"space-in-brackets": 0,
|
||||
"space-in-parens": [2, "never"],
|
||||
"space-infix-ops": [2, {"int32Hint": true}],
|
||||
"space-unary-ops": [2, { "words": true, "nonwords": false }],
|
||||
"space-unary-word-ops": 0,
|
||||
"spaced-comment": [2, "always"],
|
||||
"strict": [2, "global"],
|
||||
"use-isnan": 2,
|
||||
"valid-jsdoc": 0,
|
||||
"valid-typeof": 2,
|
||||
"vars-on-top": 0,
|
||||
"wrap-iife": 0,
|
||||
"wrap-regex": 0,
|
||||
"yoda": 2,
|
||||
|
||||
"guard-for-in": 0,
|
||||
"newline-after-var": 0,
|
||||
"no-alert": 0,
|
||||
"no-eq-null": 0,
|
||||
"no-func-assign": 0,
|
||||
"no-implied-eval": 0,
|
||||
"no-inner-declarations": 0,
|
||||
"no-invalid-regexp": 0,
|
||||
"no-irregular-whitespace": 0,
|
||||
"no-iterator": 0,
|
||||
"no-label-var": 0,
|
||||
"no-labels": 2,
|
||||
"no-lone-blocks": 0,
|
||||
"no-loop-func": 0,
|
||||
"no-negated-in-lhs": 0,
|
||||
"no-new": 0,
|
||||
"no-new-func": 0,
|
||||
"no-new-object": 0,
|
||||
"no-new-wrappers": 0,
|
||||
"no-obj-calls": 0,
|
||||
"no-octal-escape": 0,
|
||||
"no-undef-init": 2,
|
||||
"no-unexpected-multiline": 2,
|
||||
"object-curly-spacing": 0,
|
||||
"no-unused-expressions": 0,
|
||||
"no-void": 0,
|
||||
"no-wrap-func": 0,
|
||||
"operator-assignment": 0,
|
||||
"operator-linebreak": [2, "after"],
|
||||
}
|
||||
}
|
53
accessible/tests/browser/browser.ini
Normal file
53
accessible/tests/browser/browser.ini
Normal file
@ -0,0 +1,53 @@
|
||||
[DEFAULT]
|
||||
skip-if = (e10s && os == 'win') # Bug 1269369: Document loaded event does not fire in Windows
|
||||
support-files =
|
||||
events.js
|
||||
head.js
|
||||
doc_treeupdate_ariadialog.html
|
||||
doc_treeupdate_ariaowns.html
|
||||
doc_treeupdate_imagemap.html
|
||||
doc_treeupdate_removal.xhtml
|
||||
doc_treeupdate_visibility.html
|
||||
doc_treeupdate_whitespace.html
|
||||
!/accessible/tests/mochitest/*.js
|
||||
!/accessible/tests/mochitest/letters.gif
|
||||
!/accessible/tests/mochitest/moz.png
|
||||
|
||||
# Caching tests
|
||||
[browser_caching_name.js]
|
||||
skip-if = e10s
|
||||
|
||||
# Events tests
|
||||
[browser_events_caretmove.js]
|
||||
[browser_events_hide.js]
|
||||
skip-if = e10s
|
||||
[browser_events_show.js]
|
||||
skip-if = e10s
|
||||
[browser_events_statechange.js]
|
||||
[browser_events_textchange.js]
|
||||
skip-if = e10s
|
||||
|
||||
# Tree update tests
|
||||
[browser_treeupdate_ariadialog.js]
|
||||
skip-if = e10s
|
||||
[browser_treeupdate_ariaowns.js]
|
||||
skip-if = e10s
|
||||
[browser_treeupdate_canvas.js]
|
||||
skip-if = e10s
|
||||
[browser_treeupdate_cssoverflow.js]
|
||||
[browser_treeupdate_doc.js]
|
||||
skip-if = e10s
|
||||
[browser_treeupdate_gencontent.js]
|
||||
[browser_treeupdate_hidden.js]
|
||||
[browser_treeupdate_imagemap.js]
|
||||
skip-if = e10s
|
||||
[browser_treeupdate_list.js]
|
||||
[browser_treeupdate_list_editabledoc.js]
|
||||
[browser_treeupdate_listener.js]
|
||||
[browser_treeupdate_optgroup.js]
|
||||
[browser_treeupdate_removal.js]
|
||||
[browser_treeupdate_table.js]
|
||||
[browser_treeupdate_textleaf.js]
|
||||
[browser_treeupdate_visibility.js]
|
||||
[browser_treeupdate_whitespace.js]
|
||||
skip-if = true # Failing due to incorrect index of test container children on document load.
|
434
accessible/tests/browser/browser_caching_name.js
Normal file
434
accessible/tests/browser/browser_caching_name.js
Normal file
@ -0,0 +1,434 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER, EVENT_TEXT_INSERTED */
|
||||
|
||||
loadScripts({ name: 'name.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
/**
|
||||
* Rules for name tests that are inspired by
|
||||
* accessible/tests/mochitest/name/markuprules.xul
|
||||
*
|
||||
* Each element in the list of rules represents a name calculation rule for a
|
||||
* particular test case.
|
||||
*
|
||||
* The rules have the following format:
|
||||
* { attr } - calculated from attribute
|
||||
* { elm } - calculated from another element
|
||||
* { fromsubtree } - calculated from element's subtree
|
||||
*
|
||||
*
|
||||
* Options include:
|
||||
* * recreated - subrtee is recreated and the test should only continue
|
||||
* after a reorder event
|
||||
* * textchanged - text is inserted into a subtree and the test should only
|
||||
* continue after a text inserted event
|
||||
*/
|
||||
const ARIARule = [{ attr: 'aria-labelledby' }, { attr: 'aria-label' }];
|
||||
const HTMLControlHeadRule = [...ARIARule, { elm: 'label', isSibling: true }];
|
||||
const rules = {
|
||||
CSSContent: [{ elm: 'style', isSibling: true }, { fromsubtree: true }],
|
||||
HTMLARIAGridCell: [...ARIARule, { fromsubtree: true }, { attr: 'title' }],
|
||||
HTMLControl: [...HTMLControlHeadRule, { fromsubtree: true },
|
||||
{ attr: 'title' }],
|
||||
HTMLElm: [...ARIARule, { attr: 'title' }],
|
||||
HTMLImg: [...ARIARule, { attr: 'alt', recreated: true }, { attr: 'title' }],
|
||||
HTMLImgEmptyAlt: [...ARIARule, { attr: 'title' }, { attr: 'alt' }],
|
||||
HTMLInputButton: [...HTMLControlHeadRule, { attr: 'value' },
|
||||
{ attr: 'title' }],
|
||||
HTMLInputImage: [...HTMLControlHeadRule, { attr: 'alt', recreated: true },
|
||||
{ attr: 'value', recreated: true }, { attr: 'title' }],
|
||||
HTMLInputImageNoValidSrc: [...HTMLControlHeadRule,
|
||||
{ attr: 'alt', recreated: true }, { attr: 'value', recreated: true }],
|
||||
HTMLInputReset: [...HTMLControlHeadRule,
|
||||
{ attr: 'value', textchanged: true }],
|
||||
HTMLInputSubmit: [...HTMLControlHeadRule,
|
||||
{ attr: 'value', textchanged: true }],
|
||||
HTMLLink: [...ARIARule, { fromsubtree: true }, { attr: 'title' }],
|
||||
HTMLLinkImage: [...ARIARule, { elm: 'img' }, { attr: 'title' }],
|
||||
HTMLOption: [...ARIARule, { attr: 'label' }, { fromsubtree: true },
|
||||
{ attr: 'title' }],
|
||||
HTMLTable: [...ARIARule, { elm: 'caption' }, { attr: 'summary' },
|
||||
{ attr: 'title' }]
|
||||
};
|
||||
|
||||
const markupTests = [{
|
||||
id: 'btn',
|
||||
ruleset: 'HTMLControl',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn">test4</label>
|
||||
<button id="btn"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
title="test5">press me</button>`,
|
||||
expected: ['test2 test3', 'test1', 'test4', 'press me', 'test5']
|
||||
}, {
|
||||
id: 'btn',
|
||||
ruleset: 'HTMLInputButton',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn">test4</label>
|
||||
<input id="btn"
|
||||
type="button"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
value="name from value"
|
||||
alt="no name from al"
|
||||
src="no name from src"
|
||||
data="no name from data"
|
||||
title="name from title"/>`,
|
||||
expected: ['test2 test3', 'test1', 'test4', 'name from value',
|
||||
'name from title']
|
||||
}, {
|
||||
id: 'btn-submit',
|
||||
ruleset: 'HTMLInputSubmit',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn-submit">test4</label>
|
||||
<input id="btn-submit"
|
||||
type="submit"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
value="name from value"
|
||||
alt="no name from atl"
|
||||
src="no name from src"
|
||||
data="no name from data"
|
||||
title="no name from title"/>`,
|
||||
expected: ['test2 test3', 'test1', 'test4', 'name from value']
|
||||
}, {
|
||||
id: 'btn-reset',
|
||||
ruleset: 'HTMLInputReset',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn-reset">test4</label>
|
||||
<input id="btn-reset"
|
||||
type="reset"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
value="name from value"
|
||||
alt="no name from alt"
|
||||
src="no name from src"
|
||||
data="no name from data"
|
||||
title="no name from title"/>`,
|
||||
expected: ['test2 test3', 'test1', 'test4', 'name from value']
|
||||
}, {
|
||||
id: 'btn-image',
|
||||
ruleset: 'HTMLInputImage',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn-image">test4</label>
|
||||
<input id="btn-image"
|
||||
type="image"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
alt="name from alt"
|
||||
value="name from value"
|
||||
src="http://example.com/a11y/accessible/tests/mochitest/moz.png"
|
||||
data="no name from data"
|
||||
title="name from title"/>`,
|
||||
expected: ['test2 test3', 'test1', 'test4', 'name from alt',
|
||||
'name from value', 'name from title']
|
||||
}, {
|
||||
id: 'btn-image',
|
||||
ruleset: 'HTMLInputImageNoValidSrc',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn-image">test4</label>
|
||||
<input id="btn-image"
|
||||
type="image"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
alt="name from alt"
|
||||
value="name from value"
|
||||
data="no name from data"
|
||||
title="no name from title"/>`,
|
||||
expected: ['test2 test3', 'test1', 'test4', 'name from alt',
|
||||
'name from value']
|
||||
}, {
|
||||
id: 'opt',
|
||||
ruleset: 'HTMLOption',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<select>
|
||||
<option id="opt"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
label="test4"
|
||||
title="test5">option1</option>
|
||||
<option>option2</option>
|
||||
</select>`,
|
||||
expected: ['test2 test3', 'test1', 'test4', 'option1', 'test5']
|
||||
}, {
|
||||
id: 'img',
|
||||
ruleset: 'HTMLImg',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<img id="img"
|
||||
aria-label="Logo of Mozilla"
|
||||
aria-labelledby="l1 l2"
|
||||
alt="Mozilla logo"
|
||||
title="This is a logo"
|
||||
src="http://example.com/a11y/accessible/tests/mochitest/moz.png"/>`,
|
||||
expected: ['test2 test3', 'Logo of Mozilla', 'Mozilla logo', 'This is a logo']
|
||||
}, {
|
||||
id: 'imgemptyalt',
|
||||
ruleset: 'HTMLImgEmptyAlt',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<img id="imgemptyalt"
|
||||
aria-label="Logo of Mozilla"
|
||||
aria-labelledby="l1 l2"
|
||||
title="This is a logo"
|
||||
alt=""
|
||||
src="http://example.com/a11y/accessible/tests/mochitest/moz.png"/>`,
|
||||
expected: ['test2 test3', 'Logo of Mozilla', 'This is a logo', '']
|
||||
}, {
|
||||
id: 'tc',
|
||||
ruleset: 'HTMLElm',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="tc">test4</label>
|
||||
<table>
|
||||
<tr>
|
||||
<td id="tc"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
title="test5">
|
||||
<p>This is a paragraph</p>
|
||||
<a href="#">This is a link</a>
|
||||
<ul>
|
||||
<li>This is a list</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>`,
|
||||
expected: ['test2 test3', 'test1', 'test5']
|
||||
}, {
|
||||
id: 'gc',
|
||||
ruleset: 'HTMLARIAGridCell',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="gc">test4</label>
|
||||
<table>
|
||||
<tr>
|
||||
<td id="gc"
|
||||
role="gridcell"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
title="This is a paragraph This is a link This is a list">
|
||||
<p>This is a paragraph</p>
|
||||
<a href="#">This is a link</a>
|
||||
<ul>
|
||||
<li>Listitem1</li>
|
||||
<li>Listitem2</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>`,
|
||||
expected: ['test2 test3', 'test1', 'This is a paragraph',
|
||||
'This is a paragraph This is a link This is a list']
|
||||
}, {
|
||||
id: 't',
|
||||
ruleset: 'HTMLTable',
|
||||
markup: `
|
||||
<span id="l1">lby_tst6_1</span>
|
||||
<span id="l2">lby_tst6_2</span>
|
||||
<label for="t">label_tst6</label>
|
||||
<table id="t"
|
||||
aria-label="arialabel_tst6"
|
||||
aria-labelledby="l1 l2"
|
||||
summary="summary_tst6"
|
||||
title="title_tst6">
|
||||
<caption>caption_tst6</caption>
|
||||
<tr>
|
||||
<td>cell1</td>
|
||||
<td>cell2</td>
|
||||
</tr>
|
||||
</table>`,
|
||||
expected: ['lby_tst6_1 lby_tst6_2', 'arialabel_tst6', 'caption_tst6',
|
||||
'summary_tst6', 'title_tst6']
|
||||
}, {
|
||||
id: 'btn',
|
||||
ruleset: 'CSSContent',
|
||||
markup: `
|
||||
<style>
|
||||
button::before {
|
||||
content: "do not ";
|
||||
}
|
||||
</style>
|
||||
<button id="btn">press me</button>`,
|
||||
expected: ['do not press me', 'press me']
|
||||
}, {
|
||||
// TODO: uncomment when Bug-1256382 is resoved.
|
||||
// id: 'li',
|
||||
// ruleset: 'CSSContent',
|
||||
// markup: `
|
||||
// <style>
|
||||
// ul {
|
||||
// list-style-type: decimal;
|
||||
// }
|
||||
// </style>
|
||||
// <ul id="ul">
|
||||
// <li id="li">Listitem</li>
|
||||
// </ul>`,
|
||||
// expected: ['1. Listitem', `${String.fromCharCode(0x2022)} Listitem`]
|
||||
// }, {
|
||||
id: 'a',
|
||||
ruleset: 'HTMLLink',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<a id="a"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
title="test4">test5</a>`,
|
||||
expected: ['test2 test3', 'test1', 'test5', 'test4']
|
||||
}, {
|
||||
id: 'a-img',
|
||||
ruleset: 'HTMLLinkImage',
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<a id="a-img"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
title="test4"><img alt="test5"/></a>`,
|
||||
expected: ['test2 test3', 'test1', 'test5', 'test4']
|
||||
}];
|
||||
|
||||
/**
|
||||
* Wait for an accessible event to happen and, in case given accessible is
|
||||
* defunct, update it to one that is attached to the accessible event.
|
||||
* @param {Promise} onEvent accessible event promise
|
||||
* @param {Object} target { acc, parent, id } structure that contains an
|
||||
* accessible, its parent and its content element
|
||||
* id.
|
||||
*/
|
||||
function* updateAccessibleIfNeeded(onEvent, target) {
|
||||
let event = yield onEvent;
|
||||
if (isDefunct(target.acc)) {
|
||||
target.acc = findAccessibleChildByID(event.accessible, target.id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test accessible name that is calculated from an attribute, remove the
|
||||
* attribute before proceeding to the next name test. If attribute removal
|
||||
* results in a reorder or text inserted event - wait for it. If accessible
|
||||
* becomes defunct, update its reference using the one that is attached to one
|
||||
* of the above events.
|
||||
* @param {Object} browser current "tabbrowser" element
|
||||
* @param {Object} target { acc, parent, id } structure that contains an
|
||||
* accessible, its parent and its content element
|
||||
* id.
|
||||
* @param {Object} rule current attr rule for name calculation
|
||||
* @param {[type]} expected expected name value
|
||||
*/
|
||||
function* testAttrRule(browser, target, rule, expected) {
|
||||
testName(target.acc, expected);
|
||||
let onEvent;
|
||||
if (rule.recreated) {
|
||||
onEvent = waitForEvent(EVENT_REORDER, target.parent);
|
||||
} else if (rule.textchanged) {
|
||||
onEvent = waitForEvent(EVENT_TEXT_INSERTED, target.id);
|
||||
}
|
||||
yield invokeSetAttribute(browser, target.id, rule.attr);
|
||||
if (onEvent) {
|
||||
yield updateAccessibleIfNeeded(onEvent, target);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test accessible name that is calculated from an element name, remove the
|
||||
* element before proceeding to the next name test. If element removal results
|
||||
* in a reorder event - wait for it. If accessible becomes defunct, update its
|
||||
* reference using the one that is attached to a possible reorder event.
|
||||
* @param {Object} browser current "tabbrowser" element
|
||||
* @param {Object} target { acc, parent, id } structure that contains an
|
||||
* accessible, its parent and its content element
|
||||
* id.
|
||||
* @param {Object} rule current elm rule for name calculation
|
||||
* @param {[type]} expected expected name value
|
||||
*/
|
||||
function* testElmRule(browser, target, rule, expected) {
|
||||
testName(target.acc, expected);
|
||||
let onEvent = waitForEvent(EVENT_REORDER, rule.isSibling ?
|
||||
target.parent : target.id);
|
||||
yield ContentTask.spawn(browser, rule.elm, elm =>
|
||||
content.document.querySelector(`${elm}`).remove());
|
||||
yield updateAccessibleIfNeeded(onEvent, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test accessible name that is calculated from its subtree, remove the subtree
|
||||
* and wait for a reorder event before proceeding to the next name test. If
|
||||
* accessible becomes defunct, update its reference using the one that is
|
||||
* attached to a reorder event.
|
||||
* @param {Object} browser current "tabbrowser" element
|
||||
* @param {Object} target { acc, parent, id } structure that contains an
|
||||
* accessible, its parent and its content element
|
||||
* id.
|
||||
* @param {Object} rule current subtree rule for name calculation
|
||||
* @param {[type]} expected expected name value
|
||||
*/
|
||||
function* testSubtreeRule(browser, target, rule, expected) {
|
||||
testName(target.acc, expected);
|
||||
let onEvent = waitForEvent(EVENT_REORDER, target.id);
|
||||
yield ContentTask.spawn(browser, target.id, id => {
|
||||
let elm = content.document.getElementById(id);
|
||||
while (elm.firstChild) {
|
||||
elm.removeChild(elm.firstChild);
|
||||
}
|
||||
});
|
||||
yield updateAccessibleIfNeeded(onEvent, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over a list of rules and test accessible names for each one of the
|
||||
* rules.
|
||||
* @param {Object} browser current "tabbrowser" element
|
||||
* @param {Object} target { acc, parent, id } structure that contains an
|
||||
* accessible, its parent and its content element
|
||||
* id.
|
||||
* @param {Array} ruleset A list of rules to test a target with
|
||||
* @param {Array} expected A list of expected name value for each rule
|
||||
*/
|
||||
function* testNameRule(browser, target, ruleset, expected) {
|
||||
for (let i = 0; i < ruleset.length; ++i) {
|
||||
let rule = ruleset[i];
|
||||
let testFn;
|
||||
if (rule.attr) {
|
||||
testFn = testAttrRule;
|
||||
} else if (rule.elm) {
|
||||
testFn = testElmRule;
|
||||
} else if (rule.fromsubtree) {
|
||||
testFn = testSubtreeRule;
|
||||
}
|
||||
yield testFn(browser, target, rule, expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
markupTests.forEach(({ id, ruleset, markup, expected }) =>
|
||||
addAccessibleTask(markup, function*(browser, accDoc) {
|
||||
// Find a target accessible from an accessible subtree.
|
||||
let acc = findAccessibleChildByID(accDoc, id);
|
||||
// Find target's parent accessible from an accessible subtree.
|
||||
let parent = getAccessibleDOMNodeID(acc.parent);
|
||||
let target = { id, parent, acc };
|
||||
yield testNameRule(browser, target, rules[ruleset], expected);
|
||||
}));
|
21
accessible/tests/browser/browser_events_caretmove.js
Normal file
21
accessible/tests/browser/browser_events_caretmove.js
Normal file
@ -0,0 +1,21 @@
|
||||
/* 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/. */
|
||||
|
||||
/* global EVENT_TEXT_CARET_MOVED, nsIAccessibleCaretMoveEvent */
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Test caret move event and its interface:
|
||||
* - caretOffset
|
||||
*/
|
||||
addAccessibleTask('<input id="textbox" value="hello"/>', function*(browser) {
|
||||
let onCaretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, 'textbox');
|
||||
yield invokeFocus(browser, 'textbox');
|
||||
let event = yield onCaretMoved;
|
||||
|
||||
let caretMovedEvent = event.QueryInterface(nsIAccessibleCaretMoveEvent);
|
||||
is(caretMovedEvent.caretOffset, 5,
|
||||
'Correct caret offset.');
|
||||
});
|
32
accessible/tests/browser/browser_events_hide.js
Normal file
32
accessible/tests/browser/browser_events_hide.js
Normal file
@ -0,0 +1,32 @@
|
||||
/* 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/. */
|
||||
|
||||
/* global EVENT_HIDE */
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Test hide event and its interface:
|
||||
* - targetParent
|
||||
* - targetNextSibling
|
||||
* - targetPrevSibling
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
<div id="parent">
|
||||
<div id="previous"></div>
|
||||
<div id="div"></div>
|
||||
<div id="next"></div>
|
||||
</div>`, function*(browser) {
|
||||
let onHide = waitForEvent(EVENT_HIDE, 'div');
|
||||
yield invokeSetStyle(browser, 'div', 'visibility', 'hidden');
|
||||
let event = yield onHide;
|
||||
let hideEvent = event.QueryInterface(Ci.nsIAccessibleHideEvent);
|
||||
|
||||
is(getAccessibleDOMNodeID(hideEvent.targetParent), 'parent',
|
||||
'Correct target parent.');
|
||||
is(getAccessibleDOMNodeID(hideEvent.targetNextSibling), 'next',
|
||||
'Correct target next sibling.');
|
||||
is(getAccessibleDOMNodeID(hideEvent.targetPrevSibling), 'previous',
|
||||
'Correct target previous sibling.');
|
||||
});
|
17
accessible/tests/browser/browser_events_show.js
Normal file
17
accessible/tests/browser/browser_events_show.js
Normal file
@ -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/. */
|
||||
|
||||
/* global EVENT_SHOW */
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Test show event
|
||||
*/
|
||||
addAccessibleTask('<div id="div" style="visibility: hidden;"></div>',
|
||||
function*(browser) {
|
||||
let onShow = waitForEvent(EVENT_SHOW, 'div');
|
||||
yield invokeSetStyle(browser, 'div', 'visibility', 'visible');
|
||||
yield onShow;
|
||||
});
|
60
accessible/tests/browser/browser_events_statechange.js
Normal file
60
accessible/tests/browser/browser_events_statechange.js
Normal file
@ -0,0 +1,60 @@
|
||||
/* 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/. */
|
||||
|
||||
/* global STATE_CHECKED, EXT_STATE_EDITABLE, nsIAccessibleStateChangeEvent,
|
||||
EVENT_STATE_CHANGE */
|
||||
|
||||
'use strict';
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR },
|
||||
{ name: 'states.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
function checkStateChangeEvent(event, state, isExtraState, isEnabled) {
|
||||
let scEvent = event.QueryInterface(nsIAccessibleStateChangeEvent);
|
||||
is(scEvent.state, state, 'Correct state of the statechange event.');
|
||||
is(scEvent.isExtraState, isExtraState,
|
||||
'Correct extra state bit of the statechange event.');
|
||||
is(scEvent.isEnabled, isEnabled, 'Correct state of statechange event state');
|
||||
}
|
||||
|
||||
// Insert mock source into the iframe to be able to verify the right document
|
||||
// body id.
|
||||
let iframeSrc = `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<title>Inner Iframe</title>
|
||||
</head>
|
||||
<body id='iframe'></body>
|
||||
</html>`;
|
||||
|
||||
/**
|
||||
* Test state change event and its interface:
|
||||
* - state
|
||||
* - isExtraState
|
||||
* - isEnabled
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
<iframe id="iframe" src="${iframeSrc}"></iframe>
|
||||
<input id="checkbox" type="checkbox" />`, function*(browser) {
|
||||
// Test state change
|
||||
let onStateChange = waitForEvent(EVENT_STATE_CHANGE, 'checkbox');
|
||||
// Set checked for a checkbox.
|
||||
yield ContentTask.spawn(browser, {}, () =>
|
||||
content.document.getElementById('checkbox').checked = true);
|
||||
let event = yield onStateChange;
|
||||
|
||||
checkStateChangeEvent(event, STATE_CHECKED, false, true);
|
||||
testStates(event.accessible, STATE_CHECKED, 0);
|
||||
|
||||
// Test extra state
|
||||
onStateChange = waitForEvent(EVENT_STATE_CHANGE, 'iframe');
|
||||
// Set design mode on.
|
||||
yield ContentTask.spawn(browser, {}, () =>
|
||||
content.document.getElementById('iframe').contentDocument.designMode = 'on');
|
||||
event = yield onStateChange;
|
||||
|
||||
checkStateChangeEvent(event, EXT_STATE_EDITABLE, true, true);
|
||||
testStates(event.accessible, 0, EXT_STATE_EDITABLE);
|
||||
});
|
72
accessible/tests/browser/browser_events_textchange.js
Normal file
72
accessible/tests/browser/browser_events_textchange.js
Normal file
@ -0,0 +1,72 @@
|
||||
/* 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/. */
|
||||
|
||||
/* global EVENT_TEXT_INSERTED, EVENT_TEXT_REMOVED,
|
||||
nsIAccessibleTextChangeEvent */
|
||||
|
||||
'use strict';
|
||||
|
||||
function checkTextChangeEvent(event, id, text, start, end, isInserted, isFromUserInput) {
|
||||
let tcEvent = event.QueryInterface(nsIAccessibleTextChangeEvent);
|
||||
is(tcEvent.start, start, `Correct start offset for ${prettyName(id)}`);
|
||||
is(tcEvent.length, end - start, `Correct length for ${prettyName(id)}`);
|
||||
is(tcEvent.isInserted, isInserted,
|
||||
`Correct isInserted flag for ${prettyName(id)}`);
|
||||
is(tcEvent.modifiedText, text, `Correct text for ${prettyName(id)}`);
|
||||
is(tcEvent.isFromUserInput, isFromUserInput,
|
||||
`Correct value of isFromUserInput for ${prettyName(id)}`);
|
||||
}
|
||||
|
||||
function* changeText(browser, id, value, events) {
|
||||
let onEvents = waitForMultipleEvents(events.map(({ isInserted }) => {
|
||||
let eventType = isInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED;
|
||||
return { id, eventType };
|
||||
}));
|
||||
// Change text in the subtree.
|
||||
yield ContentTask.spawn(browser, { id, value }, ({ id, value }) =>
|
||||
content.document.getElementById(id).firstChild.textContent = value);
|
||||
let resolvedEvents = yield onEvents;
|
||||
|
||||
events.forEach(({ isInserted, str, offset }, idx) =>
|
||||
checkTextChangeEvent(resolvedEvents[idx],
|
||||
id, str, offset, offset + str.length, isInserted, false));
|
||||
}
|
||||
|
||||
function* removeTextFromInput(browser, id, value, start, end) {
|
||||
let onTextRemoved = waitForEvent(EVENT_TEXT_REMOVED, id);
|
||||
// Select text and delete it.
|
||||
yield ContentTask.spawn(browser, { id, start, end }, ({ id, start, end }) => {
|
||||
let el = content.document.getElementById(id);
|
||||
el.focus();
|
||||
el.setSelectionRange(start, end);
|
||||
});
|
||||
yield BrowserTestUtils.sendChar('VK_DELETE', browser);
|
||||
|
||||
let event = yield onTextRemoved;
|
||||
checkTextChangeEvent(event, id, value, start, end, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test text change event and its interface:
|
||||
* - start
|
||||
* - length
|
||||
* - isInserted
|
||||
* - modifiedText
|
||||
* - isFromUserInput
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
<p id="p">abc</p>
|
||||
<input id="input" value="input" />`, function*(browser) {
|
||||
let events = [
|
||||
{ isInserted: false, str: 'abc', offset: 0 },
|
||||
{ isInserted: true, str: 'def', offset: 0 }
|
||||
];
|
||||
yield changeText(browser, 'p', 'def', events);
|
||||
|
||||
events = [{ isInserted: true, str: 'DEF', offset: 2 }];
|
||||
yield changeText(browser, 'p', 'deDEFf', events);
|
||||
|
||||
// Test isFromUserInput property.
|
||||
yield removeTextFromInput(browser, 'input', 'n', 1, 2);
|
||||
});
|
42
accessible/tests/browser/browser_treeupdate_ariadialog.js
Normal file
42
accessible/tests/browser/browser_treeupdate_ariadialog.js
Normal file
@ -0,0 +1,42 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_SHOW, ROLE_DIALOG, ROLE_PUSHBUTTON, ROLE_TEXT_LEAF, ROLE_ENTRY,
|
||||
ROLE_DOCUMENT */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
// Test ARIA Dialog
|
||||
addAccessibleTask('doc_treeupdate_ariadialog.html', function*(browser, accDoc) {
|
||||
testAccessibleTree(accDoc, {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [ ]
|
||||
});
|
||||
|
||||
// Make dialog visible and update its inner content.
|
||||
let onShow = waitForEvent(EVENT_SHOW, 'dialog');
|
||||
yield ContentTask.spawn(browser, {}, () =>
|
||||
content.document.getElementById('dialog').style.display = 'block');
|
||||
yield onShow;
|
||||
|
||||
testAccessibleTree(accDoc, {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_DIALOG,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_PUSHBUTTON,
|
||||
children: [ { role: ROLE_TEXT_LEAF } ]
|
||||
},
|
||||
{
|
||||
role: ROLE_ENTRY
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
317
accessible/tests/browser/browser_treeupdate_ariaowns.js
Normal file
317
accessible/tests/browser/browser_treeupdate_ariaowns.js
Normal file
@ -0,0 +1,317 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
function* testContainer1(browser, accDoc) {
|
||||
const id = 't1_container';
|
||||
const docID = getAccessibleDOMNodeID(accDoc);
|
||||
const acc = findAccessibleChildByID(accDoc, id);
|
||||
|
||||
/* ================= Initial tree test ==================================== */
|
||||
// children are swapped by ARIA owns
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [
|
||||
{ SECTION: [] }
|
||||
] },
|
||||
{ PUSHBUTTON: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================ Change ARIA owns ====================================== */
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield invokeSetAttribute(browser, id, 'aria-owns', 't1_button t1_subdiv');
|
||||
yield onReorder;
|
||||
|
||||
// children are swapped again, button and subdiv are appended to
|
||||
// the children.
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // checkbox, native order
|
||||
{ PUSHBUTTON: [ ] }, // button, rearranged by ARIA own
|
||||
{ SECTION: [ ] } // subdiv from the subtree, ARIA owned
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================ Remove ARIA owns ====================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield invokeSetAttribute(browser, id, 'aria-owns');
|
||||
yield onReorder;
|
||||
|
||||
// children follow the DOM order
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ PUSHBUTTON: [ ] },
|
||||
{ CHECKBUTTON: [
|
||||
{ SECTION: [] }
|
||||
] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================ Set ARIA owns ========================================= */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield invokeSetAttribute(browser, id, 'aria-owns', 't1_button t1_subdiv');
|
||||
yield onReorder;
|
||||
|
||||
// children are swapped again, button and subdiv are appended to
|
||||
// the children.
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // checkbox
|
||||
{ PUSHBUTTON: [ ] }, // button, rearranged by ARIA own
|
||||
{ SECTION: [ ] } // subdiv from the subtree, ARIA owned
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================ Add ID to ARIA owns =================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, docID);
|
||||
yield invokeSetAttribute(browser, id, 'aria-owns',
|
||||
't1_button t1_subdiv t1_group');
|
||||
yield onReorder;
|
||||
|
||||
// children are swapped again, button and subdiv are appended to
|
||||
// the children.
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // t1_checkbox
|
||||
{ PUSHBUTTON: [ ] }, // button, t1_button
|
||||
{ SECTION: [ ] }, // subdiv from the subtree, t1_subdiv
|
||||
{ GROUPING: [ ] } // group from outside, t1_group
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================ Append element ======================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, id, id => {
|
||||
let div = content.document.createElement('div');
|
||||
div.setAttribute('id', 't1_child3');
|
||||
div.setAttribute('role', 'radio');
|
||||
content.document.getElementById(id).appendChild(div);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
// children are invalidated, they includes aria-owns swapped kids and
|
||||
// newly inserted child.
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // existing explicit, t1_checkbox
|
||||
{ RADIOBUTTON: [ ] }, // new explicit, t1_child3
|
||||
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
|
||||
{ SECTION: [ ] }, // ARIA owned, t1_subdiv
|
||||
{ GROUPING: [ ] } // ARIA owned, t1_group
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================ Remove element ======================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, {}, () =>
|
||||
content.document.getElementById('t1_span').parentNode.removeChild(
|
||||
content.document.getElementById('t1_span')));
|
||||
yield onReorder;
|
||||
|
||||
// subdiv should go away
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // explicit, t1_checkbox
|
||||
{ RADIOBUTTON: [ ] }, // explicit, t1_child3
|
||||
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
|
||||
{ GROUPING: [ ] } // ARIA owned, t1_group
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================ Remove ID ============================================= */
|
||||
onReorder = waitForEvent(EVENT_REORDER, docID);
|
||||
yield invokeSetAttribute(browser, 't1_group', 'id');
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] },
|
||||
{ RADIOBUTTON: [ ] },
|
||||
{ PUSHBUTTON: [ ] } // ARIA owned, t1_button
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================ Set ID ================================================ */
|
||||
onReorder = waitForEvent(EVENT_REORDER, docID);
|
||||
yield invokeSetAttribute(browser, 't1_grouptmp', 'id', 't1_group');
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] },
|
||||
{ RADIOBUTTON: [ ] },
|
||||
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
|
||||
{ GROUPING: [ ] } // ARIA owned, t1_group, previously t1_grouptmp
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
||||
function* removeContainer(browser, accDoc) {
|
||||
const id = 't2_container1';
|
||||
const acc = findAccessibleChildByID(accDoc, id);
|
||||
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] } // ARIA owned, 't2_owned'
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, {}, () =>
|
||||
content.document.getElementById('t2_container2').removeChild(
|
||||
content.document.getElementById('t2_container3')));
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ ]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
||||
function* stealAndRecacheChildren(browser, accDoc) {
|
||||
const id1 = 't3_container1';
|
||||
const id2 = 't3_container2';
|
||||
const acc1 = findAccessibleChildByID(accDoc, id1);
|
||||
const acc2 = findAccessibleChildByID(accDoc, id2);
|
||||
|
||||
/* ================ Steal from other ARIA owns ============================ */
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id2);
|
||||
yield invokeSetAttribute(browser, id2, 'aria-owns', 't3_child');
|
||||
yield onReorder;
|
||||
|
||||
let tree = {
|
||||
SECTION: [ ]
|
||||
};
|
||||
testAccessibleTree(acc1, tree);
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc2, tree);
|
||||
|
||||
/* ================ Append element to recache children ==================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id2);
|
||||
yield ContentTask.spawn(browser, id2, id => {
|
||||
let div = content.document.createElement('div');
|
||||
div.setAttribute('role', 'radio');
|
||||
content.document.getElementById(id).appendChild(div);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ ]
|
||||
};
|
||||
testAccessibleTree(acc1, tree);
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ RADIOBUTTON: [ ] },
|
||||
{ CHECKBUTTON: [ ] } // ARIA owned
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc2, tree);
|
||||
}
|
||||
|
||||
function* showHiddenElement(browser, accDoc) {
|
||||
const id = 't4_container1';
|
||||
const acc = findAccessibleChildByID(accDoc, id);
|
||||
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ RADIOBUTTON: [] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield invokeSetStyle(browser, 't4_child1', 'display', 'block');
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [] },
|
||||
{ RADIOBUTTON: [] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
||||
function* rearrangeARIAOwns(browser, accDoc) {
|
||||
const id = 't5_container';
|
||||
const acc = findAccessibleChildByID(accDoc, id);
|
||||
const tests = [{
|
||||
val: 't5_checkbox t5_radio t5_button',
|
||||
roleList: [ 'CHECKBUTTON', 'RADIOBUTTON', 'PUSHBUTTON' ]
|
||||
}, {
|
||||
val: 't5_radio t5_button t5_checkbox',
|
||||
roleList: [ 'RADIOBUTTON', 'PUSHBUTTON', 'CHECKBUTTON' ]
|
||||
}];
|
||||
|
||||
for (let { val, roleList } of tests) {
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield invokeSetAttribute(browser, id, 'aria-owns', val);
|
||||
yield onReorder;
|
||||
|
||||
let tree = { SECTION: [ ] };
|
||||
for (let role of roleList) {
|
||||
let ch = {};
|
||||
ch[role] = [];
|
||||
tree.SECTION.push(ch);
|
||||
}
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
}
|
||||
|
||||
function* removeNotARIAOwnedEl(browser, accDoc) {
|
||||
const id = 't6_container';
|
||||
const acc = findAccessibleChildByID(accDoc, id);
|
||||
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ TEXT_LEAF: [ ] },
|
||||
{ GROUPING: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, id, id =>
|
||||
content.document.getElementById(id).removeChild(
|
||||
content.document.getElementById('t6_span')));
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ GROUPING: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
||||
addAccessibleTask('doc_treeupdate_ariaowns.html', function*(browser, accDoc) {
|
||||
yield testContainer1(browser, accDoc);
|
||||
yield removeContainer(browser, accDoc);
|
||||
yield stealAndRecacheChildren(browser, accDoc);
|
||||
yield showHiddenElement(browser, accDoc);
|
||||
yield rearrangeARIAOwns(browser, accDoc);
|
||||
yield removeNotARIAOwnedEl(browser, accDoc);
|
||||
});
|
25
accessible/tests/browser/browser_treeupdate_canvas.js
Normal file
25
accessible/tests/browser/browser_treeupdate_canvas.js
Normal file
@ -0,0 +1,25 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_SHOW */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask(`
|
||||
<canvas id="canvas">
|
||||
<div id="dialog" role="dialog" style="display: none;"></div>
|
||||
</canvas>`, function*(browser, accDoc) {
|
||||
let canvas = findAccessibleChildByID(accDoc, 'canvas');
|
||||
let dialog = findAccessibleChildByID(accDoc, 'dialog');
|
||||
|
||||
testAccessibleTree(canvas, { CANVAS: [] });
|
||||
|
||||
let onShow = waitForEvent(EVENT_SHOW, 'dialog');
|
||||
yield invokeSetStyle(browser, 'dialog', 'display', 'block');
|
||||
yield onShow;
|
||||
|
||||
testAccessibleTree(dialog, { DIALOG: [] });
|
||||
});
|
64
accessible/tests/browser/browser_treeupdate_cssoverflow.js
Normal file
64
accessible/tests/browser/browser_treeupdate_cssoverflow.js
Normal file
@ -0,0 +1,64 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask(`
|
||||
<div id="container"><div id="scrollarea" style="overflow:auto;"><input>
|
||||
</div></div>
|
||||
<div id="container2"><div id="scrollarea2" style="overflow:hidden;">
|
||||
</div></div>`, function*(browser, accDoc) {
|
||||
const id1 = 'container';
|
||||
const id2 = 'container2';
|
||||
const container = findAccessibleChildByID(accDoc, id1);
|
||||
const container2 = findAccessibleChildByID(accDoc, id2);
|
||||
|
||||
/* ================= Change scroll range ================================== */
|
||||
let tree = {
|
||||
SECTION: [ {// container
|
||||
SECTION: [ {// scroll area
|
||||
ENTRY: [ ] // child content
|
||||
} ]
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(container, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id1);
|
||||
yield ContentTask.spawn(browser, id1, id => {
|
||||
let doc = content.document;
|
||||
doc.getElementById('scrollarea').style.width = '20px';
|
||||
doc.getElementById(id).appendChild(doc.createElement('input'));
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ {// container
|
||||
SECTION: [ {// scroll area
|
||||
ENTRY: [ ] // child content
|
||||
} ]
|
||||
}, {
|
||||
ENTRY: [ ] // inserted input
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(container, tree);
|
||||
|
||||
/* ================= Change scrollbar styles ============================== */
|
||||
tree = { SECTION: [ ] };
|
||||
testAccessibleTree(container2, tree);
|
||||
|
||||
onReorder = waitForEvent(EVENT_REORDER, id2);
|
||||
yield invokeSetStyle(browser, 'scrollarea2', 'overflow', 'auto');
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ // container
|
||||
{ SECTION: [] } // scroll area
|
||||
]
|
||||
};
|
||||
testAccessibleTree(container2, tree);
|
||||
});
|
303
accessible/tests/browser/browser_treeupdate_doc.js
Normal file
303
accessible/tests/browser/browser_treeupdate_doc.js
Normal file
@ -0,0 +1,303 @@
|
||||
/* 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';
|
||||
|
||||
/* global ROLE_PUSHBUTTON, ROLE_TEXT_LEAF, EVENT_REORDER, ROLE_DOCUMENT,
|
||||
nsIAccessibleDocument */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
const iframeSrc = `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<title>Inner Iframe</title>
|
||||
</head>
|
||||
<body id='inner-iframe'></body>
|
||||
</html>`;
|
||||
|
||||
addAccessibleTask(`
|
||||
<iframe id="iframe" src="${iframeSrc}"></iframe>`, function*(browser, accDoc) {
|
||||
// ID of the iframe that is being tested
|
||||
const id = 'inner-iframe';
|
||||
|
||||
let iframe = findAccessibleChildByID(accDoc, id);
|
||||
|
||||
/* ================= Initial tree check =================================== */
|
||||
let tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [ ]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Write iframe document ================================ */
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, id, id => {
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
let newHTMLNode = docNode.createElement('html');
|
||||
let newBodyNode = docNode.createElement('body');
|
||||
let newTextNode = docNode.createTextNode('New Wave');
|
||||
newBodyNode.id = id;
|
||||
newBodyNode.appendChild(newTextNode);
|
||||
newHTMLNode.appendChild(newBodyNode);
|
||||
docNode.replaceChild(newHTMLNode, docNode.documentElement);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: 'New Wave'
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Replace iframe HTML element ========================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, id, id => {
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
// We can't use open/write/close outside of iframe document because of
|
||||
// security error.
|
||||
let script = docNode.createElement('script');
|
||||
script.textContent = `
|
||||
document.open();
|
||||
document.write('<body id="${id}">hello</body>');
|
||||
document.close();`;
|
||||
docNode.body.appendChild(script);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: 'hello'
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Replace iframe body ================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, id, id => {
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
let newBodyNode = docNode.createElement('body');
|
||||
let newTextNode = docNode.createTextNode('New Hello');
|
||||
newBodyNode.id = id;
|
||||
newBodyNode.appendChild(newTextNode);
|
||||
newBodyNode.setAttribute('role', 'button');
|
||||
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
role: ROLE_PUSHBUTTON,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: 'New Hello'
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Open iframe document ================================= */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, id, id => {
|
||||
// Open document.
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
let script = docNode.createElement('script');
|
||||
script.textContent = `
|
||||
function closeMe() {
|
||||
document.write('Works?');
|
||||
document.close();
|
||||
}
|
||||
window.closeMe = closeMe;
|
||||
document.open();
|
||||
document.write('<body id="${id}"></body>');`;
|
||||
docNode.body.appendChild(script);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [ ]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Close iframe document ================================ */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
// Write and close document.
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
docNode.write('Works?');
|
||||
docNode.close();
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: 'Works?'
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Remove HTML from iframe document ===================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER);
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
// Remove HTML element.
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
docNode.removeChild(docNode.firstChild);
|
||||
});
|
||||
let event = yield onReorder;
|
||||
|
||||
ok(event.accessible instanceof nsIAccessibleDocument,
|
||||
'Reorder should happen on the document');
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [ ]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Insert HTML to iframe document ======================= */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, id, id => {
|
||||
// Insert HTML element.
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
let html = docNode.createElement('html');
|
||||
let body = docNode.createElement('body');
|
||||
let text = docNode.createTextNode('Haha');
|
||||
body.appendChild(text);
|
||||
body.id = id;
|
||||
html.appendChild(body);
|
||||
docNode.appendChild(html);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: 'Haha'
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Remove body from iframe document ===================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER);
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
// Remove body element.
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
docNode.documentElement.removeChild(docNode.body);
|
||||
});
|
||||
event = yield onReorder;
|
||||
|
||||
ok(event.accessible instanceof nsIAccessibleDocument,
|
||||
'Reorder should happen on the document');
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [ ]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================ Insert element under document element while body missed */
|
||||
onReorder = waitForEvent(EVENT_REORDER);
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
let inputNode = content.window.inputNode = docNode.createElement('input');
|
||||
docNode.documentElement.appendChild(inputNode);
|
||||
});
|
||||
event = yield onReorder;
|
||||
|
||||
ok(event.accessible instanceof nsIAccessibleDocument,
|
||||
'Reorder should happen on the document');
|
||||
tree = {
|
||||
DOCUMENT: [
|
||||
{ ENTRY: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
// Remove aftermath of this test before next test starts.
|
||||
docNode.documentElement.removeChild(content.window.inputNode);
|
||||
});
|
||||
|
||||
/* ================= Insert body to iframe document ======================= */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, id, id => {
|
||||
// Write and close document.
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
// Insert body element.
|
||||
let body = docNode.createElement('body');
|
||||
let text = docNode.createTextNode('Yo ho ho i butylka roma!');
|
||||
body.appendChild(text);
|
||||
body.id = id;
|
||||
docNode.documentElement.appendChild(body);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: 'Yo ho ho i butylka roma!'
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Change source ======================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, 'iframe');
|
||||
yield invokeSetAttribute(browser, 'iframe', 'src',
|
||||
`data:text/html,<html><body id="${id}"><input></body></html>`);
|
||||
event = yield onReorder;
|
||||
|
||||
tree = {
|
||||
INTERNAL_FRAME: [
|
||||
{ DOCUMENT: [
|
||||
{ ENTRY: [ ] }
|
||||
] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(event.accessible, tree);
|
||||
iframe = findAccessibleChildByID(event.accessible, id);
|
||||
|
||||
/* ================= Replace iframe body on ARIA role body ================ */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, id, id => {
|
||||
let docNode = content.document.getElementById('iframe').contentDocument;
|
||||
let newBodyNode = docNode.createElement('body');
|
||||
let newTextNode = docNode.createTextNode('New Hello');
|
||||
newBodyNode.appendChild(newTextNode);
|
||||
newBodyNode.setAttribute('role', 'button');
|
||||
newBodyNode.id = id;
|
||||
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
role: ROLE_PUSHBUTTON,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: 'New Hello'
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
});
|
78
accessible/tests/browser/browser_treeupdate_gencontent.js
Normal file
78
accessible/tests/browser/browser_treeupdate_gencontent.js
Normal file
@ -0,0 +1,78 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask(`
|
||||
<style>
|
||||
.gentext:before {
|
||||
content: "START"
|
||||
}
|
||||
.gentext:after {
|
||||
content: "END"
|
||||
}
|
||||
</style>
|
||||
<div id="container1"></div>
|
||||
<div id="container2"><div id="container2_child">text</div></div>`,
|
||||
function*(browser, accDoc) {
|
||||
const id1 = 'container1';
|
||||
const id2 = 'container2';
|
||||
let container1 = findAccessibleChildByID(accDoc, id1);
|
||||
let container2 = findAccessibleChildByID(accDoc, id2);
|
||||
|
||||
let tree = {
|
||||
SECTION: [ ] // container
|
||||
};
|
||||
testAccessibleTree(container1, tree);
|
||||
|
||||
tree = {
|
||||
SECTION: [ { // container2
|
||||
SECTION: [ { // container2 child
|
||||
TEXT_LEAF: [ ] // primary text
|
||||
} ]
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(container2, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id1);
|
||||
// Create and add an element with CSS generated content to container1
|
||||
yield ContentTask.spawn(browser, id1, id => {
|
||||
let node = content.document.createElement('div');
|
||||
node.textContent = 'text';
|
||||
node.setAttribute('class', 'gentext');
|
||||
content.document.getElementById(id).appendChild(node);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ // container
|
||||
{ SECTION: [ // inserted node
|
||||
{ STATICTEXT: [] }, // :before
|
||||
{ TEXT_LEAF: [] }, // primary text
|
||||
{ STATICTEXT: [] } // :after
|
||||
] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(container1, tree);
|
||||
|
||||
onReorder = waitForEvent(EVENT_REORDER, id2);
|
||||
// Add CSS generated content to an element in container2's subtree
|
||||
yield invokeSetAttribute(browser, 'container2_child', 'class', 'gentext');
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ // container2
|
||||
{ SECTION: [ // container2 child
|
||||
{ STATICTEXT: [] }, // :before
|
||||
{ TEXT_LEAF: [] }, // primary text
|
||||
{ STATICTEXT: [] } // :after
|
||||
] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(container2, tree);
|
||||
});
|
30
accessible/tests/browser/browser_treeupdate_hidden.js
Normal file
30
accessible/tests/browser/browser_treeupdate_hidden.js
Normal file
@ -0,0 +1,30 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
function* setHidden(browser, value) {
|
||||
let onReorder = waitForEvent(EVENT_REORDER, 'container');
|
||||
yield invokeSetAttribute(browser, 'child', 'hidden', value);
|
||||
yield onReorder;
|
||||
}
|
||||
|
||||
addAccessibleTask('<div id="container"><input id="child"></div>',
|
||||
function*(browser, accDoc) {
|
||||
let container = findAccessibleChildByID(accDoc, 'container');
|
||||
|
||||
testAccessibleTree(container, { SECTION: [ { ENTRY: [ ] } ] });
|
||||
|
||||
// Set @hidden attribute
|
||||
yield setHidden(browser, 'true');
|
||||
testAccessibleTree(container, { SECTION: [ ] });
|
||||
|
||||
// Remove @hidden attribute
|
||||
yield setHidden(browser);
|
||||
testAccessibleTree(container, { SECTION: [ { ENTRY: [ ] } ] });
|
||||
});
|
176
accessible/tests/browser/browser_treeupdate_imagemap.js
Normal file
176
accessible/tests/browser/browser_treeupdate_imagemap.js
Normal file
@ -0,0 +1,176 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER, ROLE_LINK */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
function* testImageMap(browser, accDoc) {
|
||||
const id = 'imgmap';
|
||||
const acc = findAccessibleChildByID(accDoc, id);
|
||||
|
||||
/* ================= Initial tree test ==================================== */
|
||||
let tree = {
|
||||
IMAGE_MAP: [
|
||||
{ role: ROLE_LINK, name: 'b', children: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================= Insert area ========================================== */
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let areaElm = content.document.createElement('area');
|
||||
let mapNode = content.document.getElementById('map');
|
||||
areaElm.setAttribute('href',
|
||||
'http://www.bbc.co.uk/radio4/atoz/index.shtml#a');
|
||||
areaElm.setAttribute('coords', '0,0,13,14');
|
||||
areaElm.setAttribute('alt', 'a');
|
||||
areaElm.setAttribute('shape', 'rect');
|
||||
mapNode.insertBefore(areaElm, mapNode.firstChild);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
IMAGE_MAP: [
|
||||
{ role: ROLE_LINK, name: 'a', children: [ ] },
|
||||
{ role: ROLE_LINK, name: 'b', children: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================= Append area ========================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let areaElm = content.document.createElement('area');
|
||||
let mapNode = content.document.getElementById('map');
|
||||
areaElm.setAttribute('href',
|
||||
'http://www.bbc.co.uk/radio4/atoz/index.shtml#c');
|
||||
areaElm.setAttribute('coords', '34,0,47,14');
|
||||
areaElm.setAttribute('alt', 'c');
|
||||
areaElm.setAttribute('shape', 'rect');
|
||||
mapNode.appendChild(areaElm);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
IMAGE_MAP: [
|
||||
{ role: ROLE_LINK, name: 'a', children: [ ] },
|
||||
{ role: ROLE_LINK, name: 'b', children: [ ] },
|
||||
{ role: ROLE_LINK, name: 'c', children: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================= Remove area ========================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let mapNode = content.document.getElementById('map');
|
||||
mapNode.removeChild(mapNode.firstElementChild);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
IMAGE_MAP: [
|
||||
{ role: ROLE_LINK, name: 'b', children: [ ] },
|
||||
{ role: ROLE_LINK, name: 'c', children: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
||||
function* testContainer(browser) {
|
||||
const id = 'container';
|
||||
/* ================= Remove name on map =================================== */
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield invokeSetAttribute(browser, 'map', 'name');
|
||||
let event = yield onReorder;
|
||||
const acc = event.accessible;
|
||||
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ GRAPHIC: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================= Restore name on map ================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield invokeSetAttribute(browser, 'map', 'name', 'atoz_map');
|
||||
// XXX: force repainting of the image (see bug 745788 for details).
|
||||
yield BrowserTestUtils.synthesizeMouse('#imgmap', 10, 10,
|
||||
{ type: 'mousemove' }, browser);
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ {
|
||||
IMAGE_MAP: [
|
||||
{ LINK: [ ] },
|
||||
{ LINK: [ ] }
|
||||
]
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================= Remove map =========================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let mapNode = content.document.getElementById('map');
|
||||
mapNode.parentNode.removeChild(mapNode);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ GRAPHIC: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================= Insert map =========================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, id, id => {
|
||||
let map = content.document.createElement('map');
|
||||
let area = content.document.createElement('area');
|
||||
|
||||
map.setAttribute('name', 'atoz_map');
|
||||
map.setAttribute('id', 'map');
|
||||
|
||||
area.setAttribute('href',
|
||||
'http://www.bbc.co.uk/radio4/atoz/index.shtml#b');
|
||||
area.setAttribute('coords', '17,0,30,14');
|
||||
area.setAttribute('alt', 'b');
|
||||
area.setAttribute('shape', 'rect');
|
||||
|
||||
map.appendChild(area);
|
||||
content.document.getElementById(id).appendChild(map);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ {
|
||||
IMAGE_MAP: [
|
||||
{ LINK: [ ] }
|
||||
]
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================= Hide image map ======================================= */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield invokeSetStyle(browser, 'imgmap', 'display', 'none');
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ ]
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
||||
addAccessibleTask('doc_treeupdate_imagemap.html', function*(browser, accDoc) {
|
||||
yield testImageMap(browser, accDoc);
|
||||
yield testContainer(browser);
|
||||
});
|
43
accessible/tests/browser/browser_treeupdate_list.js
Normal file
43
accessible/tests/browser/browser_treeupdate_list.js
Normal file
@ -0,0 +1,43 @@
|
||||
/* 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';
|
||||
|
||||
/* global ROLE_TEXT_LEAF, EVENT_REORDER, ROLE_STATICTEXT, ROLE_LISTITEM */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
function* setDisplayAndWaitForReorder(browser, value) {
|
||||
let onReorder = waitForEvent(EVENT_REORDER, 'ul');
|
||||
yield invokeSetStyle(browser, 'li', 'display', value);
|
||||
return yield onReorder;
|
||||
}
|
||||
|
||||
addAccessibleTask(`
|
||||
<ul id="ul">
|
||||
<li id="li">item1</li>
|
||||
</ul>`, function*(browser, accDoc) {
|
||||
let li = findAccessibleChildByID(accDoc, 'li');
|
||||
let bullet = li.firstChild;
|
||||
let accTree = {
|
||||
role: ROLE_LISTITEM,
|
||||
children: [ {
|
||||
role: ROLE_STATICTEXT,
|
||||
children: []
|
||||
}, {
|
||||
role: ROLE_TEXT_LEAF,
|
||||
children: []
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(li, accTree);
|
||||
|
||||
yield setDisplayAndWaitForReorder(browser, 'none');
|
||||
|
||||
ok(isDefunct(li), 'Check that li is defunct.');
|
||||
ok(isDefunct(bullet), 'Check that bullet is defunct.');
|
||||
|
||||
let event = yield setDisplayAndWaitForReorder(browser, 'list-item');
|
||||
|
||||
testAccessibleTree(findAccessibleChildByID(event.accessible, 'li'), accTree);
|
||||
});
|
@ -0,0 +1,39 @@
|
||||
/* 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';
|
||||
|
||||
/* global ROLE_TEXT_LEAF, EVENT_REORDER, ROLE_LISTITEM, ROLE_LIST,
|
||||
ROLE_STATICTEXT */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask('<ol id="list"></ol>', function*(browser, accDoc) {
|
||||
let list = findAccessibleChildByID(accDoc, 'list');
|
||||
|
||||
testAccessibleTree(list, {
|
||||
role: ROLE_LIST,
|
||||
children: [ ]
|
||||
});
|
||||
|
||||
yield invokeSetAttribute(browser, 'body', 'contentEditable', 'true');
|
||||
let onReorder = waitForEvent(EVENT_REORDER, 'list');
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let li = content.document.createElement('li');
|
||||
li.textContent = 'item';
|
||||
content.document.getElementById('list').appendChild(li);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
testAccessibleTree(list, {
|
||||
role: ROLE_LIST,
|
||||
children: [ {
|
||||
role: ROLE_LISTITEM,
|
||||
children: [
|
||||
{ role: ROLE_STATICTEXT, name: "1. ", children: [] },
|
||||
{ role: ROLE_TEXT_LEAF, children: [] }
|
||||
]
|
||||
} ]
|
||||
});
|
||||
});
|
43
accessible/tests/browser/browser_treeupdate_listener.js
Normal file
43
accessible/tests/browser/browser_treeupdate_listener.js
Normal file
@ -0,0 +1,43 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask('<span id="parent"><span id="child"></span></span>',
|
||||
function*(browser, accDoc) {
|
||||
is(findAccessibleChildByID(accDoc, 'parent'), null,
|
||||
'Check that parent is not accessible.');
|
||||
is(findAccessibleChildByID(accDoc, 'child'), null,
|
||||
'Check that child is not accessible.');
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, 'body');
|
||||
// Add an event listener to parent.
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
content.window.dummyListener = () => {};
|
||||
content.document.getElementById('parent').addEventListener(
|
||||
'click', content.window.dummyListener);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
let tree = { TEXT: [] };
|
||||
testAccessibleTree(findAccessibleChildByID(accDoc, 'parent'), tree);
|
||||
|
||||
onReorder = waitForEvent(EVENT_REORDER, 'body');
|
||||
// Remove an event listener from parent.
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
content.document.getElementById('parent').removeEventListener(
|
||||
'click', content.window.dummyListener);
|
||||
delete content.window.dummyListener;
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
is(findAccessibleChildByID(accDoc, 'parent'), null,
|
||||
'Check that parent is not accessible.');
|
||||
is(findAccessibleChildByID(accDoc, 'child'), null,
|
||||
'Check that child is not accessible.');
|
||||
});
|
91
accessible/tests/browser/browser_treeupdate_optgroup.js
Normal file
91
accessible/tests/browser/browser_treeupdate_optgroup.js
Normal file
@ -0,0 +1,91 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask('<select id="select"></select>', function*(browser, accDoc) {
|
||||
let select = findAccessibleChildByID(accDoc, 'select');
|
||||
|
||||
let onEvent = waitForEvent(EVENT_REORDER, 'select');
|
||||
// Create a combobox with grouping and 2 standalone options
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let doc = content.document;
|
||||
let select = doc.getElementById('select');
|
||||
let optGroup = doc.createElement('optgroup');
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
let opt = doc.createElement('option');
|
||||
opt.value = i;
|
||||
opt.text = 'Option: Value ' + i;
|
||||
optGroup.appendChild(opt);
|
||||
}
|
||||
select.add(optGroup, null);
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
let opt = doc.createElement('option');
|
||||
select.add(opt, null);
|
||||
}
|
||||
select.firstChild.firstChild.id = 'option1Node';
|
||||
});
|
||||
let event = yield onEvent;
|
||||
let option1Node = findAccessibleChildByID(event.accessible, 'option1Node');
|
||||
|
||||
let tree = {
|
||||
COMBOBOX: [ {
|
||||
COMBOBOX_LIST: [ {
|
||||
GROUPING: [
|
||||
{ COMBOBOX_OPTION: [ { TEXT_LEAF: [] } ] },
|
||||
{ COMBOBOX_OPTION: [ { TEXT_LEAF: [] } ] }
|
||||
]
|
||||
}, {
|
||||
COMBOBOX_OPTION: []
|
||||
}, {
|
||||
COMBOBOX_OPTION: []
|
||||
} ]
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(select, tree);
|
||||
ok(!isDefunct(option1Node), 'option shouldn\'t be defunct');
|
||||
|
||||
onEvent = waitForEvent(EVENT_REORDER, 'select');
|
||||
// Remove grouping from combobox
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let select = content.document.getElementById('select');
|
||||
select.removeChild(select.firstChild);
|
||||
});
|
||||
yield onEvent;
|
||||
|
||||
tree = {
|
||||
COMBOBOX: [ {
|
||||
COMBOBOX_LIST: [
|
||||
{ COMBOBOX_OPTION: [] },
|
||||
{ COMBOBOX_OPTION: [] }
|
||||
]
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(select, tree);
|
||||
ok(isDefunct(option1Node),
|
||||
'removed option shouldn\'t be accessible anymore!');
|
||||
|
||||
onEvent = waitForEvent(EVENT_REORDER, 'select');
|
||||
// Remove all options from combobox
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let select = content.document.getElementById('select');
|
||||
while (select.length) {
|
||||
select.remove(0);
|
||||
}
|
||||
});
|
||||
yield onEvent;
|
||||
|
||||
tree = {
|
||||
COMBOBOX: [ {
|
||||
COMBOBOX_LIST: [ ]
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(select, tree);
|
||||
});
|
39
accessible/tests/browser/browser_treeupdate_removal.js
Normal file
39
accessible/tests/browser/browser_treeupdate_removal.js
Normal file
@ -0,0 +1,39 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask('doc_treeupdate_removal.xhtml', function*(browser, accDoc) {
|
||||
ok(isAccessible(findAccessibleChildByID(accDoc, 'the_table')),
|
||||
'table should be accessible');
|
||||
|
||||
// Move the_table element into hidden subtree.
|
||||
let onReorder = waitForEvent(EVENT_REORDER, 'body');
|
||||
yield ContentTask.spawn(browser, {}, () => content.document.getElementById(
|
||||
'the_displaynone').appendChild(content.document.getElementById(
|
||||
'the_table')));
|
||||
yield onReorder;
|
||||
|
||||
ok(!isAccessible(findAccessibleChildByID(accDoc, 'the_table')),
|
||||
'table in display none tree shouldn\'t be accessible');
|
||||
ok(!isAccessible(findAccessibleChildByID(accDoc, 'the_row')),
|
||||
'row shouldn\'t be accessible');
|
||||
|
||||
// Remove the_row element (since it did not have accessible, no event needed).
|
||||
yield ContentTask.spawn(browser, {}, () =>
|
||||
content.document.body.removeChild(
|
||||
content.document.getElementById('the_row')));
|
||||
|
||||
// make sure no accessibles have stuck around.
|
||||
ok(!isAccessible(findAccessibleChildByID(accDoc, 'the_row')),
|
||||
'row shouldn\'t be accessible');
|
||||
ok(!isAccessible(findAccessibleChildByID(accDoc, 'the_table')),
|
||||
'table shouldn\'t be accessible');
|
||||
ok(!isAccessible(findAccessibleChildByID(accDoc, 'the_displayNone')),
|
||||
'display none things shouldn\'t be accessible');
|
||||
});
|
51
accessible/tests/browser/browser_treeupdate_table.js
Normal file
51
accessible/tests/browser/browser_treeupdate_table.js
Normal file
@ -0,0 +1,51 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask(`
|
||||
<table id="table">
|
||||
<tr>
|
||||
<td>cell1</td>
|
||||
<td>cell2</td>
|
||||
</tr>
|
||||
</table>`, function*(browser, accDoc) {
|
||||
let table = findAccessibleChildByID(accDoc, 'table');
|
||||
|
||||
let tree = {
|
||||
TABLE: [
|
||||
{ ROW: [
|
||||
{ CELL: [ {TEXT_LEAF: [] }]},
|
||||
{ CELL: [ {TEXT_LEAF: [] }]}
|
||||
] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(table, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, 'table');
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
// append a caption, it should appear as a first element in the
|
||||
// accessible tree.
|
||||
let doc = content.document;
|
||||
let caption = doc.createElement('caption');
|
||||
caption.textContent = 'table caption';
|
||||
doc.getElementById('table').appendChild(caption);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
TABLE: [
|
||||
{ CAPTION: [ { TEXT_LEAF: [] } ] },
|
||||
{ ROW: [
|
||||
{ CELL: [ {TEXT_LEAF: [] }]},
|
||||
{ CELL: [ {TEXT_LEAF: [] }]}
|
||||
] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(table, tree);
|
||||
});
|
34
accessible/tests/browser/browser_treeupdate_textleaf.js
Normal file
34
accessible/tests/browser/browser_treeupdate_textleaf.js
Normal file
@ -0,0 +1,34 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER, ROLE_TEXT_CONTAINER ROLE_PARAGRAPH, ROLE_TEXT_LEAF */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
function* removeTextData(browser, accessible, id, role) {
|
||||
let tree = {
|
||||
role: role,
|
||||
children: [ { role: ROLE_TEXT_LEAF, name: "text" } ]
|
||||
};
|
||||
testAccessibleTree(accessible, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
yield ContentTask.spawn(browser, id, id =>
|
||||
content.document.getElementById(id).firstChild.textContent = '');
|
||||
yield onReorder;
|
||||
|
||||
tree = { role: role, children: [] };
|
||||
testAccessibleTree(accessible, tree);
|
||||
}
|
||||
|
||||
addAccessibleTask(`
|
||||
<p id="p">text</p>
|
||||
<pre id="pre">text</pre>`, function*(browser, accDoc) {
|
||||
let p = findAccessibleChildByID(accDoc, 'p');
|
||||
let pre = findAccessibleChildByID(accDoc, 'pre');
|
||||
yield removeTextData(browser, p, 'p', ROLE_PARAGRAPH);
|
||||
yield removeTextData(browser, pre, 'pre', ROLE_TEXT_CONTAINER);
|
||||
});
|
196
accessible/tests/browser/browser_treeupdate_visibility.js
Normal file
196
accessible/tests/browser/browser_treeupdate_visibility.js
Normal file
@ -0,0 +1,196 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
function* testTreeOnHide(browser, accDoc, containerID, id, before, after) {
|
||||
let acc = findAccessibleChildByID(accDoc, containerID);
|
||||
testAccessibleTree(acc, before);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, containerID);
|
||||
yield invokeSetStyle(browser, id, 'visibility', 'hidden');
|
||||
yield onReorder;
|
||||
|
||||
testAccessibleTree(acc, after);
|
||||
}
|
||||
|
||||
function* test3(browser, accessible) {
|
||||
let tree = {
|
||||
SECTION: [ // container
|
||||
{ SECTION: [ // parent
|
||||
{ SECTION: [ // child
|
||||
{ TEXT_LEAF: [] }
|
||||
] }
|
||||
] },
|
||||
{ SECTION: [ // parent2
|
||||
{ SECTION: [ // child2
|
||||
{ TEXT_LEAF: [] }
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree(accessible, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, 't3_container');
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let doc = content.document;
|
||||
doc.getElementById('t3_container').style.color = 'red';
|
||||
doc.getElementById('t3_parent').style.visibility = 'hidden';
|
||||
doc.getElementById('t3_parent2').style.visibility = 'hidden';
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ // container
|
||||
{ SECTION: [ // child
|
||||
{ TEXT_LEAF: [] }
|
||||
] },
|
||||
{ SECTION: [ // child2
|
||||
{ TEXT_LEAF: [] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree(accessible, tree);
|
||||
}
|
||||
|
||||
function* test4(browser, accessible) {
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ TABLE: [
|
||||
{ ROW: [
|
||||
{ CELL: [ ] }
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree(accessible, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, 't4_parent');
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let doc = content.document;
|
||||
doc.getElementById('t4_container').style.color = 'red';
|
||||
doc.getElementById('t4_child').style.visibility = 'visible';
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [{
|
||||
TABLE: [{
|
||||
ROW: [{
|
||||
CELL: [{
|
||||
SECTION: [{
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
};
|
||||
testAccessibleTree(accessible, tree);
|
||||
}
|
||||
|
||||
addAccessibleTask('doc_treeupdate_visibility.html', function*(browser, accDoc) {
|
||||
let t3Container = findAccessibleChildByID(accDoc, 't3_container');
|
||||
let t4Container = findAccessibleChildByID(accDoc, 't4_container');
|
||||
|
||||
yield testTreeOnHide(browser, accDoc, 't1_container', 't1_parent', {
|
||||
SECTION: [{
|
||||
SECTION: [{
|
||||
SECTION: [ { TEXT_LEAF: [] } ]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
SECTION: [ {
|
||||
SECTION: [ { TEXT_LEAF: [] } ]
|
||||
} ]
|
||||
});
|
||||
|
||||
yield testTreeOnHide(browser, accDoc, 't2_container', 't2_grandparent', {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // grand parent
|
||||
SECTION: [{
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // child2
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // child2
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
});
|
||||
|
||||
yield test3(browser, t3Container);
|
||||
yield test4(browser, t4Container);
|
||||
|
||||
yield testTreeOnHide(browser, accDoc, 't5_container', 't5_subcontainer', {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // subcontainer
|
||||
TABLE: [{
|
||||
ROW: [{
|
||||
CELL: [{
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
});
|
||||
|
||||
yield testTreeOnHide(browser, accDoc, 't6_container', 't6_subcontainer', {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // subcontainer
|
||||
TABLE: [{
|
||||
ROW: [{
|
||||
CELL: [{
|
||||
TABLE: [{ // nested table
|
||||
ROW: [{
|
||||
CELL: [{
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // child2
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // child2
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
});
|
||||
});
|
71
accessible/tests/browser/browser_treeupdate_whitespace.js
Normal file
71
accessible/tests/browser/browser_treeupdate_whitespace.js
Normal file
@ -0,0 +1,71 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_REORDER */
|
||||
|
||||
loadScripts({ name: 'role.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask('doc_treeupdate_whitespace.html', function*(browser, accDoc) {
|
||||
let container1 = findAccessibleChildByID(accDoc, 'container1');
|
||||
let container2Parent = findAccessibleChildByID(accDoc, 'container2-parent');
|
||||
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ GRAPHIC: [] },
|
||||
{ TEXT_LEAF: [] },
|
||||
{ GRAPHIC: [] },
|
||||
{ TEXT_LEAF: [] },
|
||||
{ GRAPHIC: [] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(container1, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, 'container1');
|
||||
// Remove img1 from container1
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let doc = content.document;
|
||||
doc.getElementById('container1').removeChild(
|
||||
doc.getElementById('img1'));
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ GRAPHIC: [] },
|
||||
{ TEXT_LEAF: [] },
|
||||
{ GRAPHIC: [] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(container1, tree);
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ LINK: [] },
|
||||
{ LINK: [ { GRAPHIC: [] } ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(container2Parent, tree);
|
||||
|
||||
onReorder = waitForEvent(EVENT_REORDER, 'container2-parent');
|
||||
// Append an img with valid src to container2
|
||||
yield ContentTask.spawn(browser, {}, () => {
|
||||
let doc = content.document;
|
||||
let img = doc.createElement('img');
|
||||
img.setAttribute('src',
|
||||
'http://example.com/a11y/accessible/tests/mochitest/moz.png');
|
||||
doc.getElementById('container2').appendChild(img);
|
||||
});
|
||||
yield onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ LINK: [ { GRAPHIC: [ ] } ] },
|
||||
{ TEXT_LEAF: [ ] },
|
||||
{ LINK: [ { GRAPHIC: [ ] } ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(container2Parent, tree);
|
||||
});
|
23
accessible/tests/browser/doc_treeupdate_ariadialog.html
Normal file
23
accessible/tests/browser/doc_treeupdate_ariadialog.html
Normal file
@ -0,0 +1,23 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Tree Update ARIA Dialog Test</title>
|
||||
</head>
|
||||
<body id="body">
|
||||
<div id="dialog" role="dialog" style="display: none;">
|
||||
<table id="table" role="presentation"
|
||||
style="display: block; position: fixed; top: 88px; left: 312.5px; z-index: 10010;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td role="presentation">
|
||||
<div role="presentation">
|
||||
<a id="a" role="button">text</a>
|
||||
</div>
|
||||
<input id="input">
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
44
accessible/tests/browser/doc_treeupdate_ariaowns.html
Normal file
44
accessible/tests/browser/doc_treeupdate_ariaowns.html
Normal file
@ -0,0 +1,44 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Tree Update ARIA Owns Test</title>
|
||||
</head>
|
||||
<body id="body">
|
||||
<div id="t1_container" aria-owns="t1_checkbox t1_button">
|
||||
<div role="button" id="t1_button"></div>
|
||||
<div role="checkbox" id="t1_checkbox">
|
||||
<span id="t1_span">
|
||||
<div id="t1_subdiv"></div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="t1_group" role="group"></div>
|
||||
<div id="t1_grouptmp" role="group"></div>
|
||||
|
||||
<div id="t2_container1" aria-owns="t2_owned"></div>
|
||||
<div id="t2_container2">
|
||||
<div id="t2_container3"><div id="t2_owned" role="checkbox"></div></div>
|
||||
</div>
|
||||
|
||||
<div id="t3_container1" aria-owns="t3_child"></div>
|
||||
<div id="t3_child" role="checkbox"></div>
|
||||
<div id="t3_container2"></div>
|
||||
|
||||
<div id="t4_container1" aria-owns="t4_child1 t4_child2"></div>
|
||||
<div id="t4_container2">
|
||||
<div id="t4_child1" style="display:none" role="checkbox"></div>
|
||||
<div id="t4_child2" role="radio"></div>
|
||||
</div>
|
||||
|
||||
<div id="t5_container">
|
||||
<div role="button" id="t5_button"></div>
|
||||
<div role="checkbox" id="t5_checkbox"></div>
|
||||
<div role="radio" id="t5_radio"></div>
|
||||
</div>
|
||||
|
||||
<div id="t6_container" aria-owns="t6_fake">
|
||||
<span id="t6_span">hey</span>
|
||||
</div>
|
||||
<div id="t6_fake" role="group"></div>
|
||||
</body>
|
||||
</html>
|
21
accessible/tests/browser/doc_treeupdate_imagemap.html
Normal file
21
accessible/tests/browser/doc_treeupdate_imagemap.html
Normal file
@ -0,0 +1,21 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Tree Update Imagemap Test</title>
|
||||
</head>
|
||||
<body id="body">
|
||||
<map name="atoz_map" id="map">
|
||||
<area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#b"
|
||||
coords="17,0,30,14" alt="b" shape="rect">
|
||||
</map>
|
||||
|
||||
<div id="container">
|
||||
<img id="imgmap" width="447" height="15"
|
||||
usemap="#atoz_map"
|
||||
src="http://example.com/a11y/accessible/tests/mochitest/letters.gif"><!--
|
||||
Important: no whitespace between the <img> and the </div>, so we
|
||||
don't end up with textframes there, because those would be reflected
|
||||
in our accessible tree in some cases.
|
||||
--></div>
|
||||
</body>
|
||||
</html>
|
11
accessible/tests/browser/doc_treeupdate_removal.xhtml
Normal file
11
accessible/tests/browser/doc_treeupdate_removal.xhtml
Normal file
@ -0,0 +1,11 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Tree Update Removal Test</title>
|
||||
</head>
|
||||
<body id="body">
|
||||
<div id="the_displaynone" style="display: none;"></div>
|
||||
<table id="the_table"></table>
|
||||
<tr id="the_row"></tr>
|
||||
</body>
|
||||
</html>
|
78
accessible/tests/browser/doc_treeupdate_visibility.html
Normal file
78
accessible/tests/browser/doc_treeupdate_visibility.html
Normal file
@ -0,0 +1,78 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Tree Update Visibility Test</title>
|
||||
</head>
|
||||
<body id="body">
|
||||
<!-- hide parent while child stays visible -->
|
||||
<div id="t1_container">
|
||||
<div id="t1_parent">
|
||||
<div id="t1_child" style="visibility: visible">text</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- hide grandparent while its children stay visible -->
|
||||
<div id="t2_container">
|
||||
<div id="t2_grandparent">
|
||||
<div>
|
||||
<div id="t2_child" style="visibility: visible">text</div>
|
||||
<div id="t2_child2" style="visibility: visible">text</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- change container style, hide parents while their children stay visible -->
|
||||
<div id="t3_container">
|
||||
<div id="t3_parent">
|
||||
<div id="t3_child" style="visibility: visible">text</div>
|
||||
</div>
|
||||
<div id="t3_parent2">
|
||||
<div id="t3_child2" style="visibility: visible">text</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- change container style, show child inside the table -->
|
||||
<div id="t4_container">
|
||||
<table>
|
||||
<tr>
|
||||
<td id="t4_parent">
|
||||
<div id="t4_child" style="visibility: hidden;">text</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- hide subcontainer while child inside the table stays visible -->
|
||||
<div id="t5_container">
|
||||
<div id="t5_subcontainer">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div id="t5_child" style="visibility: visible;">text</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- hide subcontainer while its child and child inside the nested table stays visible -->
|
||||
<div id="t6_container">
|
||||
<div id="t6_subcontainer">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div id="t6_child" style="visibility: visible;">text</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="t6_child2" style="visibility: visible">text</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
10
accessible/tests/browser/doc_treeupdate_whitespace.html
Normal file
10
accessible/tests/browser/doc_treeupdate_whitespace.html
Normal file
@ -0,0 +1,10 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Whitespace text accessible creation/desctruction</title>
|
||||
</head>
|
||||
<body id="body">
|
||||
<div id="container1"> <img src="http://example.com/a11y/accessible/tests/mochitest/moz.png"> <img id="img1" src="http://example.com/a11y/accessible/tests/mochitest/moz.png"> <img src="http://example.com/a11y/accessible/tests/mochitest/moz.png"> </div>
|
||||
<div id="container2-parent"> <a id="container2"></a> <a><img src="http://example.com/a11y/accessible/tests/mochitest/moz.png"></a> </div>
|
||||
</body>
|
||||
</html>
|
100
accessible/tests/browser/events.js
Normal file
100
accessible/tests/browser/events.js
Normal file
@ -0,0 +1,100 @@
|
||||
/* 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';
|
||||
|
||||
/* global nsIAccessibleEvent, nsIAccessibleDocument,
|
||||
nsIAccessibleStateChangeEvent, nsIAccessibleTextChangeEvent */
|
||||
|
||||
/* exported EVENT_REORDER, EVENT_SHOW, EVENT_TEXT_INSERTED, EVENT_TEXT_REMOVED,
|
||||
EVENT_DOCUMENT_LOAD_COMPLETE, EVENT_HIDE, EVENT_TEXT_CARET_MOVED,
|
||||
EVENT_STATE_CHANGE, waitForEvent, waitForMultipleEvents */
|
||||
|
||||
const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
|
||||
const EVENT_HIDE = nsIAccessibleEvent.EVENT_HIDE;
|
||||
const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
|
||||
const EVENT_SHOW = nsIAccessibleEvent.EVENT_SHOW;
|
||||
const EVENT_STATE_CHANGE = nsIAccessibleEvent.EVENT_STATE_CHANGE;
|
||||
const EVENT_TEXT_CARET_MOVED = nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED;
|
||||
const EVENT_TEXT_INSERTED = nsIAccessibleEvent.EVENT_TEXT_INSERTED;
|
||||
const EVENT_TEXT_REMOVED = nsIAccessibleEvent.EVENT_TEXT_REMOVED;
|
||||
|
||||
/**
|
||||
* Describe an event in string format.
|
||||
* @param {nsIAccessibleEvent} event event to strigify
|
||||
*/
|
||||
function eventToString(event) {
|
||||
let type = eventTypeToString(event.eventType);
|
||||
let info = `Event type: ${type}`;
|
||||
|
||||
if (event instanceof nsIAccessibleStateChangeEvent) {
|
||||
let stateStr = statesToString(event.isExtraState ? 0 : event.state,
|
||||
event.isExtraState ? event.state : 0);
|
||||
info += `, state: ${stateStr}, is enabled: ${event.isEnabled}`;
|
||||
} else if (event instanceof nsIAccessibleTextChangeEvent) {
|
||||
let tcType = event.isInserted ? 'inserted' : 'removed';
|
||||
info += `, start: ${event.start}, length: ${event.length}, ${tcType} text: ${event.modifiedText}`;
|
||||
}
|
||||
|
||||
info += `. Target: ${prettyName(event.accessible)}`;
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that waits for an accessible event of certain type that
|
||||
* belongs to a certain DOMNode (defined by its id).
|
||||
* @param {String} id expected content element id for the event
|
||||
* @param {Number} eventType expected accessible event type
|
||||
* @return {Promise} promise that resolves to an event
|
||||
*/
|
||||
function waitForEvent(eventType, id) {
|
||||
return new Promise(resolve => {
|
||||
let eventObserver = {
|
||||
observe(subject, topic, data) {
|
||||
if (topic !== 'accessible-event') {
|
||||
return;
|
||||
}
|
||||
|
||||
let event = subject.QueryInterface(nsIAccessibleEvent);
|
||||
Logger.log(eventToString(event));
|
||||
|
||||
let domID = getAccessibleDOMNodeID(event.accessible);
|
||||
// If event's accessible does not match expected event type or DOMNode
|
||||
// id, skip thie event.
|
||||
if (domID === id && event.eventType === eventType) {
|
||||
Logger.log(`Correct event DOMNode id: ${id}`);
|
||||
Logger.log(`Correct event type: ${eventTypeToString(eventType)}`);
|
||||
ok(event.accessibleDocument instanceof nsIAccessibleDocument,
|
||||
'Accessible document present.');
|
||||
|
||||
Services.obs.removeObserver(this, 'accessible-event');
|
||||
resolve(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
Services.obs.addObserver(eventObserver, 'accessible-event', false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that waits for a sequence of accessible events in
|
||||
* specified order.
|
||||
* @param {Array} events a list of events to wait (same format as
|
||||
* waitForEvent arguments)
|
||||
*/
|
||||
function waitForMultipleEvents(events) {
|
||||
// Next expected event index.
|
||||
let currentIdx = 0;
|
||||
|
||||
return Promise.all(events.map(({ eventType, id }, idx) =>
|
||||
// In addition to waiting for an event, attach an order checker for the
|
||||
// event.
|
||||
waitForEvent(eventType, id).then(resolvedEvent => {
|
||||
// Verify that event happens in order and increment expected index.
|
||||
is(idx, currentIdx++,
|
||||
`Unexpected event order: ${eventToString(resolvedEvent)}`);
|
||||
return resolvedEvent;
|
||||
})
|
||||
));
|
||||
}
|
297
accessible/tests/browser/head.js
Normal file
297
accessible/tests/browser/head.js
Normal file
@ -0,0 +1,297 @@
|
||||
/* 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';
|
||||
|
||||
/* global EVENT_DOCUMENT_LOAD_COMPLETE */
|
||||
|
||||
/* exported Logger, MOCHITESTS_DIR, isDefunct, addAccessibleTask,
|
||||
invokeSetAttribute, invokeFocus, invokeSetStyle,
|
||||
findAccessibleChildByID, getAccessibleDOMNodeID */
|
||||
|
||||
const { interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
/**
|
||||
* Current browser test directory path used to load subscripts.
|
||||
*/
|
||||
const CURRENT_DIR =
|
||||
'chrome://mochitests/content/browser/accessible/tests/browser/';
|
||||
/**
|
||||
* A11y mochitest directory where we find common files used in both browser and
|
||||
* plain tests.
|
||||
*/
|
||||
const MOCHITESTS_DIR =
|
||||
'chrome://mochitests/content/a11y/accessible/tests/mochitest/';
|
||||
/**
|
||||
* A base URL for test files used in content.
|
||||
*/
|
||||
const CURRENT_CONTENT_DIR =
|
||||
'http://example.com/browser/accessible/tests/browser/';
|
||||
|
||||
/**
|
||||
* Used to dump debug information.
|
||||
*/
|
||||
let Logger = {
|
||||
/**
|
||||
* Set up this variable to dump log messages into console.
|
||||
*/
|
||||
dumpToConsole: false,
|
||||
|
||||
/**
|
||||
* Set up this variable to dump log messages into error console.
|
||||
*/
|
||||
dumpToAppConsole: false,
|
||||
|
||||
/**
|
||||
* Return true if dump is enabled.
|
||||
*/
|
||||
get enabled() {
|
||||
return this.dumpToConsole || this.dumpToAppConsole;
|
||||
},
|
||||
|
||||
/**
|
||||
* Dump information into console if applicable.
|
||||
*/
|
||||
log(msg) {
|
||||
if (this.enabled) {
|
||||
this.logToConsole(msg);
|
||||
this.logToAppConsole(msg);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Log message to console.
|
||||
*/
|
||||
logToConsole(msg) {
|
||||
if (this.dumpToConsole) {
|
||||
dump(`\n${msg}\n`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Log message to error console.
|
||||
*/
|
||||
logToAppConsole(msg) {
|
||||
if (this.dumpToAppConsole) {
|
||||
Services.console.logStringMessage(`${msg}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if an accessible object has a defunct test.
|
||||
* @param {nsIAccessible} accessible object to test defunct state for
|
||||
* @return {Boolean} flag indicating defunct state
|
||||
*/
|
||||
function isDefunct(accessible) {
|
||||
try {
|
||||
let extState = {};
|
||||
accessible.getState({}, extState);
|
||||
return extState.value & Ci.nsIAccessibleStates.EXT_STATE_DEFUNCT;
|
||||
} catch (x) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously set or remove content element's attribute (in content process
|
||||
* if e10s is enabled).
|
||||
* @param {Object} browser current "tabbrowser" element
|
||||
* @param {String} id content element id
|
||||
* @param {String} attr attribute name
|
||||
* @param {String?} value optional attribute value, if not present, remove
|
||||
* attribute
|
||||
* @return {Promise} promise indicating that attribute is set/removed
|
||||
*/
|
||||
function invokeSetAttribute(browser, id, attr, value) {
|
||||
if (value) {
|
||||
Logger.log(`Setting ${attr} attribute to ${value} for node with id: ${id}`);
|
||||
} else {
|
||||
Logger.log(`Removing ${attr} attribute from node with id: ${id}`);
|
||||
}
|
||||
return ContentTask.spawn(browser, { id, attr, value },
|
||||
({ id, attr, value }) => {
|
||||
let elm = content.document.getElementById(id);
|
||||
if (value) {
|
||||
elm.setAttribute(attr, value);
|
||||
} else {
|
||||
elm.removeAttribute(attr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously set or remove content element's style (in content process if
|
||||
* e10s is enabled).
|
||||
* @param {Object} browser current "tabbrowser" element
|
||||
* @param {String} id content element id
|
||||
* @param {String} aStyle style property name
|
||||
* @param {String?} aValue optional style property value, if not present,
|
||||
* remove style
|
||||
* @return {Promise} promise indicating that style is set/removed
|
||||
*/
|
||||
function invokeSetStyle(browser, id, style, value) {
|
||||
if (value) {
|
||||
Logger.log(`Setting ${style} style to ${value} for node with id: ${id}`);
|
||||
} else {
|
||||
Logger.log(`Removing ${style} style from node with id: ${id}`);
|
||||
}
|
||||
return ContentTask.spawn(browser, { id, style, value },
|
||||
({ id, style, value }) => {
|
||||
let elm = content.document.getElementById(id);
|
||||
if (value) {
|
||||
elm.style[style] = value;
|
||||
} else {
|
||||
delete elm.style[style];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously set focus on a content element (in content process if e10s is
|
||||
* enabled).
|
||||
* @param {Object} browser current "tabbrowser" element
|
||||
* @param {String} id content element id
|
||||
* @return {Promise} promise indicating that focus is set
|
||||
*/
|
||||
function invokeFocus(browser, id) {
|
||||
Logger.log(`Setting focus on a node with id: ${id}`);
|
||||
return ContentTask.spawn(browser, id, id => {
|
||||
let elm = content.document.getElementById(id);
|
||||
if (elm instanceof Ci.nsIDOMNSEditableElement && elm.editor ||
|
||||
elm instanceof Ci.nsIDOMXULTextBoxElement) {
|
||||
elm.selectionStart = elm.selectionEnd = elm.value.length;
|
||||
}
|
||||
elm.focus();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses the accessible tree starting from a given accessible as a root and
|
||||
* looks for an accessible that matches based on its DOMNode id.
|
||||
* @param {nsIAccessible} accessible root accessible
|
||||
* @param {String} id id to look up accessible for
|
||||
* @return {nsIAccessible?} found accessible if any
|
||||
*/
|
||||
function findAccessibleChildByID(accessible, id) {
|
||||
if (getAccessibleDOMNodeID(accessible) === id) {
|
||||
return accessible;
|
||||
}
|
||||
for (let i = 0; i < accessible.children.length; ++i) {
|
||||
let found = findAccessibleChildByID(accessible.getChildAt(i), id);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a list of scripts into the test
|
||||
* @param {Array} scripts a list of scripts to load
|
||||
*/
|
||||
function loadScripts(...scripts) {
|
||||
for (let script of scripts) {
|
||||
let path = typeof script === 'string' ? `${CURRENT_DIR}${script}` :
|
||||
`${script.dir}${script.name}`;
|
||||
Services.scriptloader.loadSubScript(path, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a list of frame scripts into test's content.
|
||||
* @param {Object} browser browser element that content belongs to
|
||||
* @param {Array} scripts a list of scripts to load into content
|
||||
*/
|
||||
function loadFrameScripts(browser, ...scripts) {
|
||||
let mm = browser.messageManager;
|
||||
for (let script of scripts) {
|
||||
let frameScript;
|
||||
if (typeof script === 'string') {
|
||||
if (script.includes('.js')) {
|
||||
// If script string includes a .js extention, assume it is a script
|
||||
// path.
|
||||
frameScript = `${CURRENT_DIR}${script}`;
|
||||
} else {
|
||||
// Otherwise it is a serealized script.
|
||||
frameScript = `data:,${script}`;
|
||||
}
|
||||
} else {
|
||||
// Script is a object that has { dir, name } format.
|
||||
frameScript = `${script.dir}${script.name}`;
|
||||
}
|
||||
mm.loadFrameScript(frameScript, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around browser test add_task that triggers an accessible test task
|
||||
* as a new browser test task with given document, data URL or markup snippet.
|
||||
* @param {String} doc URL (relative to current directory) or
|
||||
* data URL or markup snippet that is used
|
||||
* to test content with
|
||||
* @param {Function|Function*} task a generator or a function with tests to
|
||||
* run
|
||||
*/
|
||||
function addAccessibleTask(doc, task) {
|
||||
add_task(function*() {
|
||||
let url;
|
||||
if (doc.includes('doc_')) {
|
||||
url = `${CURRENT_CONTENT_DIR}${doc}`;
|
||||
} else {
|
||||
// Assume it's a markup snippet.
|
||||
url = `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body id="body">${doc}</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
let observers = Services.obs.enumerateObservers('accessible-event');
|
||||
while (observers.hasMoreElements()) {
|
||||
Services.obs.removeObserver(
|
||||
observers.getNext().QueryInterface(Ci.nsIObserver),
|
||||
'accessible-event');
|
||||
}
|
||||
});
|
||||
|
||||
let onDocLoad = waitForEvent(EVENT_DOCUMENT_LOAD_COMPLETE, 'body');
|
||||
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: url
|
||||
}, function*(browser) {
|
||||
registerCleanupFunction(() => {
|
||||
if (browser) {
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
if (tab && !tab.closing && tab.linkedBrowser) {
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
yield SimpleTest.promiseFocus(browser);
|
||||
|
||||
loadFrameScripts(browser,
|
||||
'let { document, window, navigator } = content;',
|
||||
{ name: 'common.js', dir: MOCHITESTS_DIR });
|
||||
|
||||
Logger.log(
|
||||
`e10s enabled: ${Services.appinfo.browserTabsRemoteAutostart}`);
|
||||
Logger.log(`Actually remote browser: ${browser.isRemoteBrowser}`);
|
||||
|
||||
let event = yield onDocLoad;
|
||||
yield task(browser, event.accessible);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as well
|
||||
// as events.js.
|
||||
loadScripts({ name: 'common.js', dir: MOCHITESTS_DIR }, 'events.js');
|
@ -88,6 +88,11 @@ const kSquareBulletText = String.fromCharCode(0x25fe) + " ";
|
||||
|
||||
const MAX_TRIM_LENGTH = 100;
|
||||
|
||||
/**
|
||||
* Services to determine if e10s is enabled.
|
||||
*/
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
/**
|
||||
* nsIAccessibleRetrieval service.
|
||||
*/
|
||||
@ -737,6 +742,31 @@ function getTextFromClipboard()
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract DOMNode id from an accessible. If e10s is enabled, DOMNode is not
|
||||
* present in parent process but, if available, DOMNode id is attached to an
|
||||
* accessible object.
|
||||
* @param {nsIAccessible} accessible accessible
|
||||
* @return {String?} DOMNode id if available
|
||||
*/
|
||||
function getAccessibleDOMNodeID(accessible) {
|
||||
if (accessible instanceof nsIAccessibleDocument) {
|
||||
// If accessible is a document, trying to find its document body id.
|
||||
try {
|
||||
return accessible.DOMNode.body.id;
|
||||
} catch (e) { /* This only works if accessible is not a proxy. */ }
|
||||
}
|
||||
try {
|
||||
return accessible.DOMNode.id;
|
||||
} catch (e) { /* This will fail if DOMNode is in different process. */ }
|
||||
try {
|
||||
// When e10s is enabled, accessible will have an "id" property if its
|
||||
// corresponding DOMNode has an id. If accessible is a document, its "id"
|
||||
// property corresponds to the "id" of its body element.
|
||||
return accessible.id;
|
||||
} catch (e) { /* This will fail if accessible is not a proxy. */ }
|
||||
}
|
||||
|
||||
/**
|
||||
* Return pretty name for identifier, it may be ID, DOM node or accessible.
|
||||
*/
|
||||
@ -755,10 +785,17 @@ function prettyName(aIdentifier)
|
||||
|
||||
if (aIdentifier instanceof nsIAccessible) {
|
||||
var acc = getAccessible(aIdentifier);
|
||||
var domID = getAccessibleDOMNodeID(acc);
|
||||
var msg = "[";
|
||||
try {
|
||||
msg += getNodePrettyName(acc.DOMNode);
|
||||
msg += ", role: " + roleToString(acc.role);
|
||||
if (Services.appinfo.browserTabsRemoteAutostart) {
|
||||
if (domID) {
|
||||
msg += `DOM node id: ${domID}, `;
|
||||
}
|
||||
} else {
|
||||
msg += `${getNodePrettyName(acc.DOMNode)}, `;
|
||||
}
|
||||
msg += "role: " + roleToString(acc.role);
|
||||
if (acc.name)
|
||||
msg += ", name: '" + shortenString(acc.name) + "'";
|
||||
} catch (e) {
|
||||
|
@ -387,9 +387,20 @@ var gPrivacyPane = {
|
||||
let msg = bundle.getFormattedString(autoStart.checked ?
|
||||
"featureEnableRequiresRestart" : "featureDisableRequiresRestart",
|
||||
[brandName]);
|
||||
let restartText = bundle.getFormattedString("okToRestartButton", [brandName]);
|
||||
let revertText = bundle.getString("revertNoRestartButton");
|
||||
|
||||
let title = bundle.getFormattedString("shouldRestartTitle", [brandName]);
|
||||
let prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService);
|
||||
let shouldProceed = prompts.confirm(window, title, msg)
|
||||
let buttonFlags = (Services.prompt.BUTTON_POS_0 *
|
||||
Services.prompt.BUTTON_TITLE_IS_STRING) +
|
||||
(Services.prompt.BUTTON_POS_1 *
|
||||
Services.prompt.BUTTON_TITLE_IS_STRING) +
|
||||
Services.prompt.BUTTON_POS_0_DEFAULT;
|
||||
|
||||
let shouldProceed = prompts.confirmEx(window, title, msg,
|
||||
buttonFlags, revertText, restartText,
|
||||
null, null, {});
|
||||
if (shouldProceed) {
|
||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
|
@ -219,6 +219,13 @@ var SessionHistoryListener = {
|
||||
// Collect data if we start with a non-empty shistory.
|
||||
if (!SessionHistory.isEmpty(docShell)) {
|
||||
this.collect();
|
||||
// When a tab is detached from the window, for the new window there is a
|
||||
// new SessionHistoryListener created. Normally it is empty at this point
|
||||
// but in a test env. the initial about:blank might have a children in which
|
||||
// case we fire off a history message here with about:blank in it. If we
|
||||
// don't do it ASAP then there is going to be a browser swap and the parent
|
||||
// will be all confused by that message.
|
||||
MessageQueue.send();
|
||||
}
|
||||
|
||||
// Listen for page title changes.
|
||||
@ -713,6 +720,8 @@ var MessageQueue = {
|
||||
}
|
||||
}
|
||||
|
||||
this._data.clear();
|
||||
|
||||
durationMs = Date.now() - durationMs;
|
||||
telemetry.FX_SESSION_RESTORE_CONTENT_COLLECT_DATA_LONGEST_OP_MS = durationMs;
|
||||
|
||||
|
@ -170,6 +170,8 @@ syncUnlinkConfirm.label=Unlink
|
||||
featureEnableRequiresRestart=%S must restart to enable this feature.
|
||||
featureDisableRequiresRestart=%S must restart to disable this feature.
|
||||
shouldRestartTitle=Restart %S
|
||||
okToRestartButton=Restart %S now
|
||||
revertNoRestartButton=Revert
|
||||
|
||||
restartNow=Restart Now
|
||||
restartLater=Restart Later
|
||||
|
@ -75,7 +75,7 @@ include(android_ndk_include)
|
||||
# This needs to happen before any compilation test is done.
|
||||
|
||||
option('--enable-macos-target', env='MACOSX_DEPLOYMENT_TARGET', nargs=1,
|
||||
default='10.6', help='Set the minimum MacOS version needed at runtime')
|
||||
default='10.7', help='Set the minimum MacOS version needed at runtime')
|
||||
|
||||
@depends('--enable-macos-target', target)
|
||||
@imports(_from='os', _import='environ')
|
||||
@ -405,20 +405,25 @@ def default_cxx_compilers(c_compiler):
|
||||
|
||||
|
||||
@template
|
||||
def compiler(language, host_or_target, c_compiler=None, other_compiler=None):
|
||||
def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
|
||||
other_c_compiler=None):
|
||||
'''Template handling the generic base checks for the compiler for the
|
||||
given `language` on the given platform (`host_or_target`).
|
||||
`host_or_target` is either `host` or `target` (the @depends functions
|
||||
from init.configure.
|
||||
When the language in 'C++', `c_compiler` is the result of the `compiler`
|
||||
When the language is 'C++', `c_compiler` is the result of the `compiler`
|
||||
template for the language 'C' for the same `host_or_target`.
|
||||
When `host_or_target` is `host`, `other_compiler` is the result of the
|
||||
`compiler` template for the same `language` for `target`.
|
||||
When `host_or_target` is `host` and the language is 'C++',
|
||||
`other_c_compiler` is the result of the `compiler` template for the
|
||||
language 'C' for `target`.
|
||||
'''
|
||||
assert host_or_target in (host, target)
|
||||
assert language in ('C', 'C++')
|
||||
assert language == 'C' or c_compiler
|
||||
assert host_or_target == target or other_compiler
|
||||
assert language == 'C' or host_or_target == target or other_c_compiler
|
||||
|
||||
host_or_target_str = {
|
||||
host: 'host',
|
||||
@ -462,14 +467,19 @@ def compiler(language, host_or_target, c_compiler=None, other_compiler=None):
|
||||
flags=cmd[len(without_flags):],
|
||||
)
|
||||
|
||||
# Derive the host C compiler from the target C compiler when no explicit
|
||||
# compiler was given and we're not cross compiling.
|
||||
if language == 'C' and host_or_target == host:
|
||||
@depends(provided_compiler, other_compiler, cross_compiling)
|
||||
def provided_compiler(value, other_compiler, cross_compiling):
|
||||
# Derive the host compiler from the corresponding target compiler when no
|
||||
# explicit compiler was given and we're not cross compiling. For the C++
|
||||
# compiler, though, prefer to derive from the host C compiler when it
|
||||
# doesn't match the target C compiler.
|
||||
if host_or_target == host:
|
||||
args = (c_compiler, other_c_compiler) if other_c_compiler else ()
|
||||
|
||||
@depends(provided_compiler, other_compiler, cross_compiling, *args)
|
||||
def provided_compiler(value, other_compiler, cross_compiling, *args):
|
||||
if value:
|
||||
return value
|
||||
if not cross_compiling:
|
||||
c_compiler, other_c_compiler = args if args else (None, None)
|
||||
if not cross_compiling and c_compiler == other_c_compiler:
|
||||
return other_compiler
|
||||
|
||||
# Normally, we'd use `var` instead of `_var`, but the interaction with
|
||||
@ -607,4 +617,5 @@ c_compiler = compiler('C', target)
|
||||
cxx_compiler = compiler('C++', target, c_compiler=c_compiler)
|
||||
host_c_compiler = compiler('C', host, other_compiler=c_compiler)
|
||||
host_cxx_compiler = compiler('C++', host, c_compiler=host_c_compiler,
|
||||
other_compiler=cxx_compiler)
|
||||
other_compiler=cxx_compiler,
|
||||
other_c_compiler=c_compiler)
|
||||
|
@ -16,7 +16,7 @@
|
||||
<body role="application" class="theme-body">
|
||||
<form id="options-panel">
|
||||
<div id="tools-box" class="options-vertical-pane">
|
||||
<fieldset id="default-tools-box" class="options-groupbox" tabindex="0">
|
||||
<fieldset id="default-tools-box" class="options-groupbox">
|
||||
<legend>&options.selectDefaultTools.label;</legend>
|
||||
</fieldset>
|
||||
|
||||
|
@ -264,3 +264,29 @@
|
||||
margin: 2px 0px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Keyboard focus highlight styles */
|
||||
|
||||
:-moz-focusring {
|
||||
outline: var(--theme-focus-outline);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
textbox[focused="true"] {
|
||||
border-color: var(--theme-focus-border-color-textbox);
|
||||
box-shadow: var(--theme-focus-box-shadow-textbox);
|
||||
transition: all 0.2s ease-in-out
|
||||
}
|
||||
|
||||
textbox :-moz-focusring {
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Form fields should already have box-shadow hightlight */
|
||||
select:-moz-focusring,
|
||||
input[type="radio"]:-moz-focusring,
|
||||
input[type="checkbox"]:-moz-focusring,
|
||||
checkbox:-moz-focusring {
|
||||
outline: none;
|
||||
}
|
||||
|
@ -150,13 +150,6 @@
|
||||
margin: 2px 1px;
|
||||
}
|
||||
|
||||
.devtools-menulist:-moz-focusring,
|
||||
.devtools-toolbarbutton:-moz-focusring,
|
||||
.devtools-button:-moz-focusring {
|
||||
outline: 1px dotted hsla(210,30%,85%,0.7);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
.devtools-toolbarbutton:not([label]) > .toolbarbutton-icon,
|
||||
.devtools-button::before {
|
||||
width: 16px;
|
||||
@ -185,6 +178,10 @@
|
||||
transition: opacity 0.05s ease-in-out;
|
||||
}
|
||||
|
||||
.devtools-button:-moz-focusring {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Standalone buttons */
|
||||
.devtools-button[standalone],
|
||||
.devtools-button[data-standalone],
|
||||
@ -436,6 +433,14 @@
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.devtools-searchbox > .devtools-textinput:-moz-focusring,
|
||||
.devtools-searchbox > .devtools-searchinput:-moz-focusring {
|
||||
border-color: var(--theme-focus-border-color-textbox);
|
||||
box-shadow: var(--theme-focus-box-shadow-textbox);
|
||||
transition: all 0.2s ease-in-out;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Don't add 'double spacing' for inputs that are at beginning / end
|
||||
of a toolbar (since the toolbar has it's own spacing). */
|
||||
.devtools-toolbar > .devtools-textinput:first-child,
|
||||
|
@ -43,6 +43,10 @@
|
||||
--theme-highlight-red: #ed2655;
|
||||
--theme-highlight-pink: #b82ee5;
|
||||
|
||||
/* For accessibility purposes we want to enhance the focus styling. This
|
||||
* should improve keyboard navigation usability. */
|
||||
--theme-focus-outline-color: #000000;
|
||||
|
||||
/* Colors used in Graphs, like performance tools. Similar colors to Chrome's timeline. */
|
||||
--theme-graphs-green: #85d175;
|
||||
--theme-graphs-blue: #83b7f6;
|
||||
@ -89,6 +93,10 @@
|
||||
--theme-highlight-red: #eb5368;
|
||||
--theme-highlight-pink: #df80ff;
|
||||
|
||||
/* For accessibility purposes we want to enhance the focus styling. This
|
||||
* should improve keyboard navigation usability. */
|
||||
--theme-focus-outline-color: #ced3d9;
|
||||
|
||||
/* Colors used in Graphs, like performance tools. Mostly similar to some "highlight-*" colors. */
|
||||
--theme-graphs-green: #70bf53;
|
||||
--theme-graphs-blue: #46afe3;
|
||||
@ -158,3 +166,15 @@
|
||||
rgba(0, 0, 0, 0.1),
|
||||
transparent) repeat-x;
|
||||
}
|
||||
|
||||
:root {
|
||||
--theme-focus-border-color-textbox: #0675d3;
|
||||
--theme-textbox-box-shadow: rgba(97,181,255,.75);
|
||||
|
||||
/* For accessibility purposes we want to enhance the focus styling. This
|
||||
* should improve keyboard navigation usability. */
|
||||
--theme-focus-outline: 1px dotted var(--theme-focus-outline-color);
|
||||
--theme-focus-box-shadow-textbox: 0 0 0 1px var(--theme-textbox-box-shadow);
|
||||
--theme-focus-box-shadow-inset-bottom: 0 -2px 1px var(--theme-textbox-box-shadow) inset,
|
||||
0px -2px var(--theme-highlight-blue) inset;
|
||||
}
|
||||
|
@ -406,11 +406,17 @@ a {
|
||||
.jsterm-input-node,
|
||||
.jsterm-complete-node {
|
||||
border: none;
|
||||
padding: 0 0 0 16px;
|
||||
padding: 4px;
|
||||
padding-inline-start: 20px;
|
||||
margin: 0;
|
||||
-moz-appearance: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.jsterm-input-node[focused="true"] {
|
||||
box-shadow: var(--theme-focus-box-shadow-inset-bottom);
|
||||
}
|
||||
|
||||
.jsterm-complete-node {
|
||||
color: var(--theme-comment);
|
||||
}
|
||||
@ -422,6 +428,7 @@ a {
|
||||
background-image: var(--command-line-image);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px 16px;
|
||||
background-position: 4px 50%;
|
||||
color: var(--theme-content-color1);
|
||||
}
|
||||
|
||||
|
@ -249,6 +249,15 @@
|
||||
color: hsl(210,30%,85%);
|
||||
}
|
||||
|
||||
.breadcrumbs-widget-item:-moz-focusring {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.breadcrumbs-widget-item[checked]:-moz-focusring > .button-box {
|
||||
outline: var(--theme-focus-outline);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
.breadcrumbs-widget-item > .button-box {
|
||||
border: none;
|
||||
padding-top: 0;
|
||||
|
@ -41,6 +41,7 @@ interface nsIContentViewer : nsISupports
|
||||
|
||||
[noscript,notxpcom,nostdcall] void loadStart(in nsIDocument aDoc);
|
||||
void loadComplete(in nsresult aStatus);
|
||||
[noscript] readonly attribute boolean loadCompleted;
|
||||
|
||||
/**
|
||||
* Checks if the document wants to prevent unloading by firing beforeunload on
|
||||
|
@ -37,9 +37,9 @@ public:
|
||||
delete_(JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
|
||||
JS::ObjectOpResult &aResult) const override;
|
||||
|
||||
// No need for getPrototypeIfOrdinary here: this object shouldn't have a
|
||||
// lazy prototype, so this trap would never be called (and the inherited
|
||||
// version, from BaseProxyHandler, just crashes).
|
||||
// No need for getPrototypeIfOrdinary here: window named-properties objects
|
||||
// have static prototypes, so the version inherited from BaseDOMProxyHandler
|
||||
// will do the right thing.
|
||||
|
||||
virtual bool
|
||||
preventExtensions(JSContext* aCx, JS::Handle<JSObject*> aProxy,
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "mozilla/css/Loader.h"
|
||||
#include "mozilla/dom/SRILogHelper.h"
|
||||
#include "nsStyleLinkElement.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsILoadContext.h"
|
||||
@ -53,13 +54,6 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static LogModule*
|
||||
GetSriLog()
|
||||
{
|
||||
static LazyLogModule gSriPRLog("SRI");
|
||||
return gSriPRLog;
|
||||
}
|
||||
|
||||
LazyLogModule gContentSinkLogModuleInfo("nscontentsink");
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentSink)
|
||||
@ -762,7 +756,7 @@ nsContentSink::ProcessStyleLink(nsIContent* aElement,
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity, integrity);
|
||||
}
|
||||
if (!integrity.IsEmpty()) {
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
MOZ_LOG(dom::SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("nsContentSink::ProcessStyleLink, integrity=%s",
|
||||
NS_ConvertUTF16toUTF8(integrity).get()));
|
||||
}
|
||||
|
@ -7378,27 +7378,31 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
|
||||
RefPtr<mozilla::gfx::SourceSurface> surface =
|
||||
image->GetFrame(imgIContainer::FRAME_CURRENT,
|
||||
imgIContainer::FLAG_SYNC_DECODE);
|
||||
if (surface) {
|
||||
RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
|
||||
surface->GetDataSurface();
|
||||
size_t length;
|
||||
int32_t stride;
|
||||
mozilla::UniquePtr<char[]> surfaceData =
|
||||
nsContentUtils::GetSurfaceData(dataSurface, &length, &stride);
|
||||
|
||||
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
|
||||
item->flavor() = flavorStr;
|
||||
// Turn item->data() into an nsCString prior to accessing it.
|
||||
item->data() = EmptyCString();
|
||||
item->data().get_nsCString().Adopt(surfaceData.release(), length);
|
||||
|
||||
IPCDataTransferImage& imageDetails = item->imageDetails();
|
||||
mozilla::gfx::IntSize size = dataSurface->GetSize();
|
||||
imageDetails.width() = size.width;
|
||||
imageDetails.height() = size.height;
|
||||
imageDetails.stride() = stride;
|
||||
imageDetails.format() = static_cast<uint8_t>(dataSurface->GetFormat());
|
||||
if (!surface) {
|
||||
continue;
|
||||
}
|
||||
RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
|
||||
surface->GetDataSurface();
|
||||
if (!dataSurface) {
|
||||
continue;
|
||||
}
|
||||
size_t length;
|
||||
int32_t stride;
|
||||
mozilla::UniquePtr<char[]> surfaceData =
|
||||
nsContentUtils::GetSurfaceData(dataSurface, &length, &stride);
|
||||
|
||||
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
|
||||
item->flavor() = flavorStr;
|
||||
// Turn item->data() into an nsCString prior to accessing it.
|
||||
item->data() = EmptyCString();
|
||||
item->data().get_nsCString().Adopt(surfaceData.release(), length);
|
||||
|
||||
IPCDataTransferImage& imageDetails = item->imageDetails();
|
||||
mozilla::gfx::IntSize size = dataSurface->GetSize();
|
||||
imageDetails.width() = size.width;
|
||||
imageDetails.height() = size.height;
|
||||
imageDetails.stride() = stride;
|
||||
imageDetails.format() = static_cast<uint8_t>(dataSurface->GetFormat());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -1020,10 +1020,28 @@ nsFrameLoader::SwapWithOtherRemoteLoader(nsFrameLoader* aOther,
|
||||
ourDoc->FlushPendingNotifications(Flush_Layout);
|
||||
otherDoc->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
// Initialize browser API if needed now that owner content has changed.
|
||||
InitializeBrowserAPI();
|
||||
aOther->InitializeBrowserAPI();
|
||||
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
|
||||
Unused << mRemoteBrowser->SendSwappedWithOtherRemoteLoader();
|
||||
Unused << aOther->mRemoteBrowser->SendSwappedWithOtherRemoteLoader();
|
||||
// Send an updated tab context since owner content type may have changed.
|
||||
MutableTabContext ourContext;
|
||||
rv = GetNewTabContext(&ourContext);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
MutableTabContext otherContext;
|
||||
rv = aOther->GetNewTabContext(&otherContext);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
Unused << mRemoteBrowser->SendSwappedWithOtherRemoteLoader(
|
||||
ourContext.AsIPCTabContext());
|
||||
Unused << aOther->mRemoteBrowser->SendSwappedWithOtherRemoteLoader(
|
||||
otherContext.AsIPCTabContext());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1429,6 +1447,10 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
ourParentDocument->FlushPendingNotifications(Flush_Layout);
|
||||
otherParentDocument->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
// Initialize browser API if needed now that owner content has changed
|
||||
InitializeBrowserAPI();
|
||||
aOther->InitializeBrowserAPI();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -925,13 +925,14 @@ nsOuterWindowProxy::getPrototypeIfOrdinary(JSContext* cx,
|
||||
//
|
||||
// https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof
|
||||
//
|
||||
// We nonetheless can implement it here using a non-"lazy" [[Prototype]],
|
||||
// because wrapper-class handlers (particularly, XOW in FilteringWrapper.cpp)
|
||||
// supply all the non-ordinary behavior.
|
||||
// We nonetheless can implement it with a static [[Prototype]], because
|
||||
// wrapper-class handlers (particularly, XOW in FilteringWrapper.cpp) supply
|
||||
// all non-ordinary behavior.
|
||||
//
|
||||
// But from a spec point of view, it's the exact same object in both cases --
|
||||
// only the observer's changed. So both cases *must* report non-ordinary,
|
||||
// even if non-"lazy" [[Prototype]] usually means ordinary.
|
||||
// only the observer's changed. So this getPrototypeIfOrdinary trap on the
|
||||
// non-wrapper object *must* report non-ordinary, even if static [[Prototype]]
|
||||
// usually means ordinary.
|
||||
*isOrdinary = false;
|
||||
return true;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "nsJSUtils.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/SRILogHelper.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
@ -60,13 +61,6 @@ using namespace mozilla::dom;
|
||||
|
||||
static LazyLogModule gCspPRLog("CSP");
|
||||
|
||||
static LogModule*
|
||||
GetSriLog()
|
||||
{
|
||||
static LazyLogModule gSriPRLog("SRI");
|
||||
return gSriPRLog;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS0(nsScriptLoadRequest)
|
||||
|
||||
nsScriptLoadRequestList::~nsScriptLoadRequestList()
|
||||
@ -550,7 +544,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
||||
scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity,
|
||||
integrity);
|
||||
if (!integrity.IsEmpty()) {
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("nsScriptLoader::ProcessScriptElement, integrity=%s",
|
||||
NS_ConvertUTF16toUTF8(integrity).get()));
|
||||
SRICheck::IntegrityMetadata(integrity, mDocument, &sriMetadata);
|
||||
@ -1431,7 +1425,7 @@ nsScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||
bool enforceSRI = false;
|
||||
loadInfo->GetEnforceSRI(&enforceSRI);
|
||||
if (enforceSRI) {
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("nsScriptLoader::OnStreamComplete, required SRI not found"));
|
||||
rv = NS_ERROR_SRI_CORRUPT;
|
||||
}
|
||||
@ -1657,7 +1651,7 @@ nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
|
||||
|
||||
SRIMetadata sriMetadata;
|
||||
if (!aIntegrity.IsEmpty()) {
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("nsScriptLoader::PreloadURI, integrity=%s",
|
||||
NS_ConvertUTF16toUTF8(aIntegrity).get()));
|
||||
SRICheck::IntegrityMetadata(aIntegrity, mDocument, &sriMetadata);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/FragmentOrElement.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/dom/SRILogHelper.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
@ -35,13 +36,6 @@
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static LogModule*
|
||||
GetSriLog()
|
||||
{
|
||||
static LazyLogModule gSriPRLog("SRI");
|
||||
return gSriPRLog;
|
||||
}
|
||||
|
||||
nsStyleLinkElement::nsStyleLinkElement()
|
||||
: mDontLoadStyle(false)
|
||||
, mUpdatesEnabled(true)
|
||||
@ -435,7 +429,7 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
|
||||
nsAutoString integrity;
|
||||
thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity, integrity);
|
||||
if (!integrity.IsEmpty()) {
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("nsStyleLinkElement::DoUpdateStyleSheet, integrity=%s",
|
||||
NS_ConvertUTF16toUTF8(integrity).get()));
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ Test swapFrameLoaders with different frame types and remoteness
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestLongerTimeout(100);
|
||||
|
||||
window.open("window_swapFrameLoaders.xul", "bug1242644",
|
||||
"chrome,width=600,height=600");
|
||||
|
@ -36,6 +36,20 @@ Test swapFrameLoaders with different frame types and remoteness
|
||||
["html", "html", "remote"],
|
||||
];
|
||||
|
||||
const HEIGHTS = [
|
||||
200,
|
||||
400
|
||||
];
|
||||
|
||||
function frameScript() {
|
||||
addEventListener("load", function onLoad() {
|
||||
sendAsyncMessage("test:load");
|
||||
}, true);
|
||||
}
|
||||
|
||||
// Watch for loads in new frames
|
||||
window.messageManager.loadFrameScript(`data:,(${frameScript})();`, true);
|
||||
|
||||
function once(target, eventName, useCapture = false) {
|
||||
info("Waiting for event: '" + eventName + "' on " + target + ".");
|
||||
|
||||
@ -56,7 +70,7 @@ Test swapFrameLoaders with different frame types and remoteness
|
||||
});
|
||||
}
|
||||
|
||||
function* addFrame(type, remote) {
|
||||
function* addFrame(type, remote, height) {
|
||||
let frame = document.createElementNS(NS[type], TAG[type]);
|
||||
frame.setAttribute("remote", remote);
|
||||
if (remote && type == "xul") {
|
||||
@ -69,8 +83,12 @@ Test swapFrameLoaders with different frame types and remoteness
|
||||
} else if (type == "xul") {
|
||||
frame.setAttribute("type", "content");
|
||||
}
|
||||
frame.setAttribute("src", "about:blank");
|
||||
let src = `data:text/html,<!doctype html>` +
|
||||
`<body style="height:${height}px"/>`;
|
||||
frame.setAttribute("src", src);
|
||||
document.documentElement.appendChild(frame);
|
||||
let mm = frame.frameLoader.messageManager;
|
||||
yield once(mm, "test:load");
|
||||
return frame;
|
||||
}
|
||||
|
||||
@ -86,11 +104,13 @@ Test swapFrameLoaders with different frame types and remoteness
|
||||
for (let scenario of SCENARIOS) {
|
||||
let [ typeA, typeB, remote ] = scenario;
|
||||
remote = !!remote;
|
||||
info(`Adding frame A, type ${typeA}, remote ${remote}`);
|
||||
let frameA = yield addFrame(typeA, remote);
|
||||
let heightA = HEIGHTS[0];
|
||||
info(`Adding frame A, type ${typeA}, remote ${remote}, height ${heightA}`);
|
||||
let frameA = yield addFrame(typeA, remote, heightA);
|
||||
|
||||
info(`Adding frame B, type ${typeB}, remote ${remote}`);
|
||||
let frameB = yield addFrame(typeB, remote);
|
||||
let heightB = HEIGHTS[1];
|
||||
info(`Adding frame B, type ${typeB}, remote ${remote}, height ${heightB}`);
|
||||
let frameB = yield addFrame(typeB, remote, heightB);
|
||||
|
||||
let frameScriptFactory = function(name) {
|
||||
return `function() {
|
||||
@ -128,6 +148,18 @@ Test swapFrameLoaders with different frame types and remoteness
|
||||
is(pongB, "B", "Frame B message manager gets reply B before swap");
|
||||
}
|
||||
|
||||
// Check height before swap
|
||||
{
|
||||
if (frameA.getContentDimensions) {
|
||||
let { height } = yield frameA.getContentDimensions();
|
||||
is(height, heightA, "Frame A's content height is 200px before swap");
|
||||
}
|
||||
if (frameB.getContentDimensions) {
|
||||
let { height } = yield frameB.getContentDimensions();
|
||||
is(height, heightB, "Frame B's content height is 400px before swap");
|
||||
}
|
||||
}
|
||||
|
||||
// Ping after swap using message managers acquired before
|
||||
{
|
||||
let mmA = frameA.frameLoader.messageManager;
|
||||
@ -150,6 +182,18 @@ Test swapFrameLoaders with different frame types and remoteness
|
||||
is(pongB, "A", "Frame B message manager acquired before swap gets reply A after swap");
|
||||
}
|
||||
|
||||
// Check height after swap
|
||||
{
|
||||
if (frameA.getContentDimensions) {
|
||||
let { height } = yield frameA.getContentDimensions();
|
||||
is(height, heightB, "Frame A's content height is 400px after swap");
|
||||
}
|
||||
if (frameB.getContentDimensions) {
|
||||
let { height } = yield frameB.getContentDimensions();
|
||||
is(height, heightA, "Frame B's content height is 200px after swap");
|
||||
}
|
||||
}
|
||||
|
||||
// Ping after swap using message managers acquired after
|
||||
{
|
||||
let mmA = frameA.frameLoader.messageManager;
|
||||
|
@ -11666,6 +11666,23 @@ class CGDOMJSProxyHandler_getInstance(ClassMethod):
|
||||
""")
|
||||
|
||||
|
||||
class CGDOMJSProxyHandler_getPrototypeIfOrdinary(ClassMethod):
|
||||
def __init__(self):
|
||||
args = [Argument('JSContext*', 'cx'),
|
||||
Argument('JS::Handle<JSObject*>', 'proxy'),
|
||||
Argument('bool*', 'isOrdinary'),
|
||||
Argument('JS::MutableHandle<JSObject*>', 'proto')]
|
||||
|
||||
ClassMethod.__init__(self, "getPrototypeIfOrdinary", "bool", args,
|
||||
virtual=True, override=True, const=True)
|
||||
|
||||
def getBody(self):
|
||||
return dedent("""
|
||||
*isOrdinary = false;
|
||||
return true;
|
||||
""")
|
||||
|
||||
|
||||
class CGDOMJSProxyHandler_call(ClassMethod):
|
||||
def __init__(self):
|
||||
args = [Argument('JSContext*', 'cx'),
|
||||
@ -11697,7 +11714,8 @@ class CGDOMJSProxyHandler_isCallable(ClassMethod):
|
||||
class CGDOMJSProxyHandler(CGClass):
|
||||
def __init__(self, descriptor):
|
||||
assert (descriptor.supportsIndexedProperties() or
|
||||
descriptor.supportsNamedProperties())
|
||||
descriptor.supportsNamedProperties() or
|
||||
descriptor.hasNonOrdinaryGetPrototypeOf())
|
||||
methods = [CGDOMJSProxyHandler_getOwnPropDescriptor(descriptor),
|
||||
CGDOMJSProxyHandler_defineProperty(descriptor),
|
||||
ClassUsingDeclaration("mozilla::dom::DOMProxyHandler",
|
||||
@ -11724,6 +11742,8 @@ class CGDOMJSProxyHandler(CGClass):
|
||||
(descriptor.operations['NamedSetter'] is not None and
|
||||
descriptor.interface.getExtendedAttribute('OverrideBuiltins'))):
|
||||
methods.append(CGDOMJSProxyHandler_setCustom(descriptor))
|
||||
if descriptor.hasNonOrdinaryGetPrototypeOf():
|
||||
methods.append(CGDOMJSProxyHandler_getPrototypeIfOrdinary())
|
||||
if descriptor.operations['LegacyCaller']:
|
||||
methods.append(CGDOMJSProxyHandler_call())
|
||||
methods.append(CGDOMJSProxyHandler_isCallable())
|
||||
|
@ -515,7 +515,8 @@ class Descriptor(DescriptorProvider):
|
||||
|
||||
self.proxy = (self.supportsIndexedProperties() or
|
||||
(self.supportsNamedProperties() and
|
||||
not self.hasNamedPropertiesObject))
|
||||
not self.hasNamedPropertiesObject) or
|
||||
self.hasNonOrdinaryGetPrototypeOf())
|
||||
|
||||
if self.proxy:
|
||||
if (not self.operations['IndexedGetter'] and
|
||||
@ -747,6 +748,9 @@ class Descriptor(DescriptorProvider):
|
||||
def supportsNamedProperties(self):
|
||||
return self.operations['NamedGetter'] is not None
|
||||
|
||||
def hasNonOrdinaryGetPrototypeOf(self):
|
||||
return self.interface.getExtendedAttribute("NonOrdinaryGetPrototypeOf")
|
||||
|
||||
def needsConstructHookHolder(self):
|
||||
assert self.interface.hasInterfaceObject()
|
||||
return False
|
||||
|
@ -251,6 +251,16 @@ BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx,
|
||||
return ownPropNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
|
||||
}
|
||||
|
||||
bool
|
||||
BaseDOMProxyHandler::getPrototypeIfOrdinary(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
bool* isOrdinary,
|
||||
JS::MutableHandle<JSObject*> proto) const
|
||||
{
|
||||
*isOrdinary = true;
|
||||
proto.set(GetStaticPrototype(proxy));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaseDOMProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy,
|
||||
|
@ -59,6 +59,10 @@ public:
|
||||
virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::AutoIdVector &props) const override;
|
||||
|
||||
virtual bool getPrototypeIfOrdinary(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
bool* isOrdinary,
|
||||
JS::MutableHandle<JSObject*> proto) const override;
|
||||
|
||||
// We override getOwnEnumerablePropertyKeys() and implement it directly
|
||||
// instead of using the default implementation, which would call
|
||||
// ownPropertyKeys and then filter out the non-enumerable ones. This avoids
|
||||
|
@ -1464,7 +1464,8 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
identifier == "Unforgeable" or
|
||||
identifier == "UnsafeInPrerendering" or
|
||||
identifier == "LegacyEventInit" or
|
||||
identifier == "ProbablyShortLivingObject"):
|
||||
identifier == "ProbablyShortLivingObject" or
|
||||
identifier == "NonOrdinaryGetPrototypeOf"):
|
||||
# Known extended attributes that do not take values
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[%s] must take no arguments" % identifier,
|
||||
|
@ -33,47 +33,48 @@ function isTopBrowserElement(docShell) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!('BrowserElementIsPreloaded' in this)) {
|
||||
if (isTopBrowserElement(docShell)) {
|
||||
if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
|
||||
try {
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
|
||||
} catch (e) {
|
||||
if (!BrowserElementIsReady) {
|
||||
if (!('BrowserElementIsPreloaded' in this)) {
|
||||
if (isTopBrowserElement(docShell)) {
|
||||
if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
|
||||
try {
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
// general content apps
|
||||
if (isTopBrowserElement(docShell)) {
|
||||
if(Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
// general content apps
|
||||
if (isTopBrowserElement(docShell)) {
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js");
|
||||
}
|
||||
} else {
|
||||
// rocketbar in system app and other in-process case (ex. B2G desktop client)
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js");
|
||||
}
|
||||
|
||||
if (Services.prefs.getIntPref("dom.w3c_touch_events.enabled") != 0) {
|
||||
if (docShell.asyncPanZoomEnabled === false) {
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanningAPZDisabled.js");
|
||||
ContentPanningAPZDisabled.init();
|
||||
}
|
||||
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js");
|
||||
ContentPanning.init();
|
||||
}
|
||||
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js");
|
||||
} else {
|
||||
// rocketbar in system app and other in-process case (ex. B2G desktop client)
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js");
|
||||
}
|
||||
|
||||
if (Services.prefs.getIntPref("dom.w3c_touch_events.enabled") != 0) {
|
||||
if (docShell.asyncPanZoomEnabled === false) {
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanningAPZDisabled.js");
|
||||
ContentPanningAPZDisabled.init();
|
||||
if (Services.prefs.getIntPref("dom.w3c_touch_events.enabled") != 0) {
|
||||
if (docShell.asyncPanZoomEnabled === false) {
|
||||
ContentPanningAPZDisabled.init();
|
||||
}
|
||||
ContentPanning.init();
|
||||
}
|
||||
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js");
|
||||
ContentPanning.init();
|
||||
}
|
||||
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js");
|
||||
} else {
|
||||
if (Services.prefs.getIntPref("dom.w3c_touch_events.enabled") != 0) {
|
||||
if (docShell.asyncPanZoomEnabled === false) {
|
||||
ContentPanningAPZDisabled.init();
|
||||
}
|
||||
ContentPanning.init();
|
||||
}
|
||||
}
|
||||
|
||||
var BrowserElementIsReady = true;
|
||||
|
||||
|
||||
sendAsyncMessage('browser-element-api:call', { 'msg_name': 'hello' });
|
||||
|
@ -2174,7 +2174,6 @@ CanvasRenderingContext2D::CreatePattern(const CanvasImageSource& aSource,
|
||||
nsLayoutUtils::SFE_WANT_FIRST_FRAME, mTarget);
|
||||
|
||||
if (!res.GetSourceSurface()) {
|
||||
aError.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
#include "WebGLElementArrayCache.cpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include "nscore.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
@ -21,7 +21,7 @@ VerifyImplFunction(bool condition, const char* file, int line)
|
||||
if (condition) {
|
||||
gTestsPassed++;
|
||||
} else {
|
||||
std::cerr << "Test failed at " << file << ":" << line << std::endl;
|
||||
std::fprintf(stderr, "Test failed at %s:%d\n", file, line);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
@ -226,7 +226,7 @@ main(int argc, char* argv[])
|
||||
} // i
|
||||
} // maxBufferSize
|
||||
|
||||
std::cerr << argv[0] << ": all " << gTestsPassed << " tests passed" << std::endl;
|
||||
std::fprintf(stderr, "%s: all %d tests passed\n", argv[0], gTestsPassed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ skip-if = (os == 'b2g')
|
||||
[test_bug422132.html]
|
||||
skip-if = buildapp == 'b2g' # b2g(2 failures out of 8, mousewheel test) b2g-debug(2 failures out of 8, mousewheel test) b2g-desktop(2 failures out of 8, mousewheel test)
|
||||
[test_bug426082.html]
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || os == "win" || toolkit == 'android' || e10s # Intermittent failures, bug 921693 # b2g(1 failure out of 6, Moving the mouse down from the label should have unpressed the button) b2g-debug(1 failure out of 6, Moving the mouse down from the label should have unpressed the button) b2g-desktop(1 failure out of 6, Moving the mouse down from the label should have unpressed the button)
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || os == "win" || toolkit == 'android' # b2g(1 failure out of 6, Moving the mouse down from the label should have unpressed the button) b2g-debug(1 failure out of 6, Moving the mouse down from the label should have unpressed the button) b2g-desktop(1 failure out of 6, Moving the mouse down from the label should have unpressed the button)
|
||||
[test_bug427537.html]
|
||||
[test_bug1003432.html]
|
||||
support-files = test_bug1003432.js
|
||||
@ -105,7 +105,7 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
|
||||
[test_bug650493.html]
|
||||
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
|
||||
[test_bug656379-1.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' || e10s #TIMED_OUT #Bug 931116, b2g desktop specific, initial triage
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_bug656379-2.html]
|
||||
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
|
||||
[test_bug656954.html]
|
||||
|
@ -840,16 +840,6 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
||||
tabId, *ipcContext, aChromeFlags,
|
||||
GetID(), IsForApp(), IsForBrowser());
|
||||
|
||||
nsAutoCString url;
|
||||
if (aURI) {
|
||||
aURI->GetSpec(url);
|
||||
} else {
|
||||
// We can't actually send a nullptr up as the URI, since IPDL doesn't let us
|
||||
// send nullptr's for primitives. We indicate that the nsString for the URI
|
||||
// should be converted to a nullptr by voiding the string.
|
||||
url.SetIsVoid(true);
|
||||
}
|
||||
|
||||
nsString name(aName);
|
||||
nsAutoCString features(aFeatures);
|
||||
nsTArray<FrameScriptInfo> frameScripts;
|
||||
@ -861,6 +851,16 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
||||
|
||||
if (aIframeMoz) {
|
||||
MOZ_ASSERT(aTabOpener);
|
||||
nsAutoCString url;
|
||||
if (aURI) {
|
||||
aURI->GetSpec(url);
|
||||
} else {
|
||||
// We can't actually send a nullptr up as the URI, since IPDL doesn't let us
|
||||
// send nullptr's for primitives. We indicate that the nsString for the URI
|
||||
// should be converted to a nullptr by voiding the string.
|
||||
url.SetIsVoid(true);
|
||||
}
|
||||
|
||||
newChild->SendBrowserFrameOpenWindow(aTabOpener, renderFrame, NS_ConvertUTF8toUTF16(url),
|
||||
name, NS_ConvertUTF8toUTF16(features),
|
||||
aWindowIsNew, &textureFactoryIdentifier,
|
||||
@ -895,7 +895,7 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
||||
nsresult rv;
|
||||
if (!SendCreateWindow(aTabOpener, newChild, renderFrame,
|
||||
aChromeFlags, aCalledFromJS, aPositionSpecified,
|
||||
aSizeSpecified, url,
|
||||
aSizeSpecified,
|
||||
name, features,
|
||||
baseURIString,
|
||||
openerDocShell
|
||||
|
@ -5363,7 +5363,6 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
||||
const bool& aCalledFromJS,
|
||||
const bool& aPositionSpecified,
|
||||
const bool& aSizeSpecified,
|
||||
const nsCString& aURI,
|
||||
const nsString& aName,
|
||||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
@ -5496,44 +5495,13 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
||||
return true;
|
||||
}
|
||||
|
||||
// WindowWatcher is going to expect a valid URI to open a window
|
||||
// to. If it can't find one, it's going to attempt to figure one
|
||||
// out on its own, which is problematic because it can't access
|
||||
// the document for the remote browser we're opening. Luckily,
|
||||
// TabChild has sent us a baseURI with which we can ensure that
|
||||
// the URI we pass to WindowWatcher is valid.
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
*aResult = NS_NewURI(getter_AddRefs(baseURI), aBaseURI);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(*aResult))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsAutoCString finalURIString;
|
||||
if (!aURI.IsEmpty()) {
|
||||
nsCOMPtr<nsIURI> finalURI;
|
||||
*aResult = NS_NewURI(getter_AddRefs(finalURI), aURI.get(), baseURI);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(*aResult))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
finalURI->GetSpec(finalURIString);
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIDOMWindowProxy> window;
|
||||
|
||||
TabParent::AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
|
||||
|
||||
// If nsWindowWatcher::OpenWindowInternal was passed a nullptr for the URI
|
||||
// to open in the content process, we indicate that by sending up a voided
|
||||
// nsString (since primitives are not nullable). If we detect the voided
|
||||
// nsString, we know that we need to send OpenWindow2 a nullptr for the URI.
|
||||
const char* uri = aURI.IsVoid() ? nullptr : finalURIString.get();
|
||||
const char* name = aName.IsVoid() ? nullptr : NS_ConvertUTF16toUTF8(aName).get();
|
||||
const char* features = aFeatures.IsVoid() ? nullptr : aFeatures.get();
|
||||
|
||||
*aResult = pwwatch->OpenWindow2(parent, uri, name, features, aCalledFromJS,
|
||||
*aResult = pwwatch->OpenWindow2(parent, nullptr, name, features, aCalledFromJS,
|
||||
false, false, thisTabParent, nullptr,
|
||||
aFullZoom, 1, getter_AddRefs(window));
|
||||
|
||||
|
@ -502,7 +502,6 @@ public:
|
||||
const bool& aCalledFromJS,
|
||||
const bool& aPositionSpecified,
|
||||
const bool& aSizeSpecified,
|
||||
const nsCString& aURI,
|
||||
const nsString& aName,
|
||||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
|
@ -19,6 +19,7 @@ include DOMTypes;
|
||||
include JavaScriptTypes;
|
||||
include URIParams;
|
||||
include BrowserConfiguration;
|
||||
include PTabContext;
|
||||
|
||||
|
||||
using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
|
||||
@ -724,7 +725,7 @@ child:
|
||||
* Tell the browser that its frame loader has been swapped
|
||||
* with another.
|
||||
*/
|
||||
async SwappedWithOtherRemoteLoader();
|
||||
async SwappedWithOtherRemoteLoader(IPCTabContext context);
|
||||
|
||||
/**
|
||||
* A potential accesskey was just pressed. Look for accesskey targets
|
||||
|
@ -1137,7 +1137,6 @@ parent:
|
||||
bool aCalledFromJS,
|
||||
bool aPositionSpecified,
|
||||
bool aSizeSpecified,
|
||||
nsCString aURI,
|
||||
nsString aName,
|
||||
nsCString aFeatures,
|
||||
nsCString aBaseURI,
|
||||
|
@ -2287,7 +2287,7 @@ TabChild::RecvAppOfflineStatus(const uint32_t& aId, const bool& aOffline)
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvSwappedWithOtherRemoteLoader()
|
||||
TabChild::RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext)
|
||||
{
|
||||
nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
|
||||
if (NS_WARN_IF(!ourDocShell)) {
|
||||
@ -2307,6 +2307,29 @@ TabChild::RecvSwappedWithOtherRemoteLoader()
|
||||
|
||||
nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, false);
|
||||
nsContentUtils::FirePageHideEvent(ourDocShell, ourEventTarget);
|
||||
|
||||
// Owner content type may have changed, so store the possibly updated context
|
||||
// and notify others.
|
||||
MaybeInvalidTabContext maybeContext(aContext);
|
||||
if (!maybeContext.IsValid()) {
|
||||
NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
|
||||
"the parent process. (%s)",
|
||||
maybeContext.GetInvalidReason()).get());
|
||||
MOZ_CRASH("Invalid TabContext received from the parent process.");
|
||||
}
|
||||
|
||||
if (!UpdateTabContextAfterSwap(maybeContext.GetTabContext())) {
|
||||
MOZ_CRASH("Update to TabContext after swap was denied.");
|
||||
}
|
||||
NotifyTabContextUpdated();
|
||||
|
||||
// Ignore previous value of mTriedBrowserInit since owner content has changed.
|
||||
mTriedBrowserInit = true;
|
||||
// Initialize the child side of the browser element machinery, if appropriate.
|
||||
if (IsMozBrowserOrApp()) {
|
||||
RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
|
||||
}
|
||||
|
||||
nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, true);
|
||||
|
||||
docShell->SetInFrameSwap(false);
|
||||
|
@ -417,7 +417,8 @@ public:
|
||||
virtual bool RecvAppOfflineStatus(const uint32_t& aId,
|
||||
const bool& aOffline) override;
|
||||
|
||||
virtual bool RecvSwappedWithOtherRemoteLoader() override;
|
||||
virtual bool
|
||||
RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext) override;
|
||||
|
||||
virtual PDocAccessibleChild*
|
||||
AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&) override;
|
||||
|
@ -159,6 +159,25 @@ TabContext::SetTabContext(const TabContext& aContext)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabContext::UpdateTabContextAfterSwap(const TabContext& aContext)
|
||||
{
|
||||
// This is only used after already initialized.
|
||||
MOZ_ASSERT(mInitialized);
|
||||
|
||||
// The only permissable change is to `mIsMozBrowserElement`. All other fields
|
||||
// must match for the change to be accepted.
|
||||
if (aContext.OwnAppId() != OwnAppId() ||
|
||||
aContext.mContainingAppId != mContainingAppId ||
|
||||
aContext.mOriginAttributes != mOriginAttributes ||
|
||||
aContext.mSignedPkgOriginNoSuffix != mSignedPkgOriginNoSuffix) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mIsMozBrowserElement = aContext.mIsMozBrowserElement;
|
||||
return true;
|
||||
}
|
||||
|
||||
const DocShellOriginAttributes&
|
||||
TabContext::OriginAttributesRef() const
|
||||
{
|
||||
|
@ -160,6 +160,17 @@ protected:
|
||||
const DocShellOriginAttributes& aOriginAttributes,
|
||||
const nsACString& aSignedPkgOriginNoSuffix);
|
||||
|
||||
/**
|
||||
* Modify this TabContext to match the given TabContext. This is a special
|
||||
* case triggered by nsFrameLoader::SwapWithOtherRemoteLoader which may have
|
||||
* caused the owner content to change.
|
||||
*
|
||||
* This special case only allows the field `mIsMozBrowserElement` to be
|
||||
* changed. If any other fields have changed, the update is ignored and
|
||||
* returns false.
|
||||
*/
|
||||
bool UpdateTabContextAfterSwap(const TabContext& aContext);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Has this TabContext been initialized? If so, mutator methods will fail.
|
||||
|
@ -27,6 +27,7 @@ mozilla::LazyLogModule gMP3DemuxerLog("MP3Demuxer");
|
||||
#endif
|
||||
|
||||
using mozilla::media::TimeUnit;
|
||||
using mozilla::media::TimeInterval;
|
||||
using mozilla::media::TimeIntervals;
|
||||
using mp4_demuxer::ByteReader;
|
||||
|
||||
@ -325,13 +326,33 @@ MP3TrackDemuxer::GetResourceOffset() const {
|
||||
|
||||
TimeIntervals
|
||||
MP3TrackDemuxer::GetBuffered() {
|
||||
TimeUnit duration = Duration();
|
||||
|
||||
if (duration <= TimeUnit()) {
|
||||
return TimeIntervals();
|
||||
}
|
||||
AutoPinned<MediaResource> stream(mSource.GetResource());
|
||||
return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
|
||||
TimeIntervals buffered;
|
||||
|
||||
if (Duration() > TimeUnit() && stream->IsDataCachedToEndOfResource(0)) {
|
||||
// Special case completely cached files. This also handles local files.
|
||||
buffered += TimeInterval(TimeUnit(), Duration());
|
||||
MP3LOGV("buffered = [[%" PRId64 ", %" PRId64 "]]",
|
||||
TimeUnit().ToMicroseconds(), Duration().ToMicroseconds());
|
||||
return buffered;
|
||||
}
|
||||
|
||||
MediaByteRangeSet ranges;
|
||||
nsresult rv = stream->GetCachedRanges(ranges);
|
||||
NS_ENSURE_SUCCESS(rv, buffered);
|
||||
|
||||
for (const auto& range: ranges) {
|
||||
if (range.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
TimeUnit start = Duration(FrameIndexFromOffset(range.mStart));
|
||||
TimeUnit end = Duration(FrameIndexFromOffset(range.mEnd));
|
||||
MP3LOGV("buffered += [%" PRId64 ", %" PRId64 "]",
|
||||
start.ToMicroseconds(), end.ToMicroseconds());
|
||||
buffered += TimeInterval(start, end);
|
||||
}
|
||||
|
||||
return buffered;
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
@ -694,6 +694,7 @@ tags=msg
|
||||
[test_mediarecorder_getencodeddata.html]
|
||||
tags=msg
|
||||
[test_mediarecorder_principals.html]
|
||||
skip-if = (os == 'linux' && bits == 64) # See bug 1266345
|
||||
tags=msg
|
||||
[test_mediarecorder_record_4ch_audiocontext.html]
|
||||
tags=msg
|
||||
|
@ -10,6 +10,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
<head>
|
||||
<title>Test for Bug 1170817</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/push/test/test_utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
@ -24,65 +25,54 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function generateURL() {
|
||||
return "worker.js" + "?" + (Math.random());
|
||||
}
|
||||
|
||||
var registration;
|
||||
add_task(function* start() {
|
||||
yield setupPrefsAndMockSocket(new MockWebSocket());
|
||||
yield setPushPermission(true);
|
||||
|
||||
function start() {
|
||||
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
|
||||
.then(swr => { registration = swr; return swr; });
|
||||
}
|
||||
registration = yield navigator.serviceWorker.register(
|
||||
generateURL(), {scope: "."});
|
||||
});
|
||||
|
||||
function unregisterSW() {
|
||||
return registration.unregister().then(function(result) {
|
||||
ok(result, "Unregister should return true.");
|
||||
}, function(e) {
|
||||
dump("Unregistering the SW failed with " + e + "\n");
|
||||
});
|
||||
}
|
||||
var pushSubscription;
|
||||
add_task(function* setupPushNotification() {
|
||||
pushSubscription = yield registration.pushManager.subscribe();
|
||||
ok(pushSubscription, "successful registered for push notification");
|
||||
});
|
||||
|
||||
function setupPushNotification(swr) {
|
||||
return swr.pushManager.subscribe().then(
|
||||
pushSubscription => {
|
||||
ok(true, "successful registered for push notification");
|
||||
return pushSubscription;
|
||||
}, error => {
|
||||
ok(false, "could not register for push notification");
|
||||
});
|
||||
}
|
||||
add_task(function* unregisterPushNotification() {
|
||||
var result = yield pushSubscription.unsubscribe();
|
||||
ok(result, "unsubscribe() on existing subscription should return true.");
|
||||
});
|
||||
|
||||
function unregisterPushNotification(pushSubscription) {
|
||||
return pushSubscription.unsubscribe().then(
|
||||
result => {
|
||||
ok(result, "unsubscribe() on existing subscription should return true.");
|
||||
return pushSubscription;
|
||||
}, error => {
|
||||
ok(false, "unsubscribe() should never fail.");
|
||||
});
|
||||
}
|
||||
add_task(function* unregisterAgain() {
|
||||
var result = yield pushSubscription.unsubscribe();
|
||||
ok(!result, "unsubscribe() on previously unsubscribed subscription should return false.");
|
||||
});
|
||||
|
||||
function unregisterAgain(pushSubscription) {
|
||||
return pushSubscription.unsubscribe().then(
|
||||
result => {
|
||||
ok(!result, "unsubscribe() on previously unsubscribed subscription should return false.");
|
||||
return pushSubscription;
|
||||
}, error => {
|
||||
ok(false, "unsubscribe() should never fail.");
|
||||
});
|
||||
}
|
||||
add_task(function* subscribeAgain() {
|
||||
pushSubscription = yield registration.pushManager.subscribe();
|
||||
ok(pushSubscription, "Should create a new push subscription");
|
||||
|
||||
function runTest() {
|
||||
start()
|
||||
.then(setupPushNotification)
|
||||
.then(unregisterPushNotification)
|
||||
.then(unregisterAgain)
|
||||
.then(unregisterSW)
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e);
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
var result = yield registration.unregister();
|
||||
ok(result, "Should unregister the service worker");
|
||||
|
||||
registration = yield navigator.serviceWorker.register(
|
||||
generateURL(), {scope: "."});
|
||||
var pushSubscription = yield registration.pushManager.getSubscription();
|
||||
ok(!pushSubscription,
|
||||
"Unregistering a service worker should drop its subscription");
|
||||
});
|
||||
|
||||
add_task(function* unregister() {
|
||||
var result = yield registration.unregister();
|
||||
ok(result, "Unregister should return true.");
|
||||
});
|
||||
|
||||
setupPrefsAndMockSocket(new MockWebSocket()).then(_ => runTest());
|
||||
SpecialPowers.addPermission("desktop-notification", true, document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/SRILogHelper.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIDocument.h"
|
||||
@ -21,15 +22,10 @@
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsWhitespaceTokenizer.h"
|
||||
|
||||
static mozilla::LogModule*
|
||||
GetSriLog()
|
||||
{
|
||||
static mozilla::LazyLogModule gSriPRLog("SRI");
|
||||
return gSriPRLog;
|
||||
}
|
||||
|
||||
#define SRILOG(args) MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug, args)
|
||||
#define SRIERROR(args) MOZ_LOG(GetSriLog(), mozilla::LogLevel::Error, args)
|
||||
#define SRILOG(args) \
|
||||
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug, args)
|
||||
#define SRIERROR(args) \
|
||||
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Error, args)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -66,7 +62,7 @@ IsEligible(nsIChannel* aChannel, const CORSMode aCORSMode,
|
||||
rv = originalURI->GetSpec(requestSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
nsAutoCString documentSpec, finalSpec;
|
||||
aDocument->GetDocumentURI()->GetAsciiSpec(documentSpec);
|
||||
if (finalURI) {
|
||||
@ -150,7 +146,7 @@ SRICheck::IntegrityMetadata(const nsAString& aMetadataList,
|
||||
}
|
||||
|
||||
nsAutoCString alg1, alg2;
|
||||
if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
outMetadata->GetAlgorithm(&alg1);
|
||||
metadata.GetAlgorithm(&alg2);
|
||||
}
|
||||
@ -165,7 +161,7 @@ SRICheck::IntegrityMetadata(const nsAString& aMetadataList,
|
||||
}
|
||||
}
|
||||
|
||||
if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
if (outMetadata->IsValid()) {
|
||||
nsAutoCString alg;
|
||||
outMetadata->GetAlgorithm(&alg);
|
||||
@ -192,7 +188,7 @@ SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata,
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
aLoader->GetChannel(getter_AddRefs(channel));
|
||||
|
||||
if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
nsAutoCString requestURL;
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
if (channel &&
|
||||
@ -345,7 +341,7 @@ SRICheckDataVerifier::Verify(const SRIMetadata& aMetadata,
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDocument);
|
||||
|
||||
if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
|
||||
nsAutoCString requestURL;
|
||||
nsCOMPtr<nsIRequest> request;
|
||||
request = do_QueryInterface(aChannel);
|
||||
|
28
dom/security/SRILogHelper.h
Normal file
28
dom/security/SRILogHelper.h
Normal file
@ -0,0 +1,28 @@
|
||||
/* -*- 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_SRILogHelper_h
|
||||
#define mozilla_dom_SRILogHelper_h
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SRILogHelper final
|
||||
{
|
||||
public:
|
||||
static LogModule* GetSriLog()
|
||||
{
|
||||
static LazyLogModule gSriPRLog("SRI");
|
||||
return gSriPRLog;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_SRILogHelper_h
|
@ -14,6 +14,7 @@ EXPORTS.mozilla.dom += [
|
||||
'nsCSPUtils.h',
|
||||
'nsMixedContentBlocker.h',
|
||||
'SRICheck.h',
|
||||
'SRILogHelper.h',
|
||||
'SRIMetadata.h',
|
||||
]
|
||||
|
||||
|
@ -70,6 +70,23 @@ nsSVGViewBox::Init()
|
||||
mAnimVal = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGViewBox::HasRect() const
|
||||
{
|
||||
// Check mAnimVal if we have one; otherwise, check mBaseVal if we have one;
|
||||
// otherwise, just return false (we clearly do not have a rect).
|
||||
const nsSVGViewBoxRect* rect = mAnimVal;
|
||||
if (!rect) {
|
||||
if (!mHasBaseVal) {
|
||||
// no anim val, no base val --> no viewbox rect
|
||||
return false;
|
||||
}
|
||||
rect = &mBaseVal;
|
||||
}
|
||||
|
||||
return !rect->none && rect->width >= 0 && rect->height >= 0;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGViewBox::SetAnimValue(const nsSVGViewBoxRect& aRect,
|
||||
nsSVGElement *aSVGElement)
|
||||
|
@ -52,11 +52,7 @@ public:
|
||||
* string, or if any of the four rect values were too big to store in a
|
||||
* float, or the width/height are negative.
|
||||
*/
|
||||
bool HasRect() const
|
||||
{
|
||||
const nsSVGViewBoxRect& rect = GetAnimValue();
|
||||
return !rect.none && rect.width >= 0 && rect.height >= 0;
|
||||
}
|
||||
bool HasRect() const;
|
||||
|
||||
/**
|
||||
* Returns true if the corresponding "viewBox" attribute either defined a
|
||||
|
@ -123,7 +123,7 @@ var interfaceNamesInGlobalScope =
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"AnalyserNode",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "Animation", release: false},
|
||||
{name: "Animation"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "AnimationEffectReadOnly", release: false},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -69,7 +69,7 @@ interface CanvasRenderingContext2D {
|
||||
[NewObject, Throws]
|
||||
CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1);
|
||||
[NewObject, Throws]
|
||||
CanvasPattern createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition);
|
||||
CanvasPattern? createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition);
|
||||
|
||||
// shadows
|
||||
[LenientFloat]
|
||||
|
@ -11,7 +11,7 @@
|
||||
* and create derivative works of this document.
|
||||
*/
|
||||
|
||||
[Unforgeable]
|
||||
[Unforgeable, NonOrdinaryGetPrototypeOf]
|
||||
interface Location {
|
||||
// Bug 824857: no support for stringifier attributes yet.
|
||||
// stringifier attribute USVString href;
|
||||
|
@ -6,10 +6,44 @@
|
||||
|
||||
#include "ServiceWorkerUnregisterJob.h"
|
||||
|
||||
#include "nsIPushService.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
class ServiceWorkerUnregisterJob::PushUnsubscribeCallback final :
|
||||
public nsIUnsubscribeResultCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit PushUnsubscribeCallback(ServiceWorkerUnregisterJob* aJob)
|
||||
: mJob(aJob)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OnUnsubscribe(nsresult aStatus, bool) override
|
||||
{
|
||||
// Warn if unsubscribing fails, but don't prevent the worker from
|
||||
// unregistering.
|
||||
Unused << NS_WARN_IF(NS_FAILED(aStatus));
|
||||
mJob->Unregister();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~PushUnsubscribeCallback()
|
||||
{
|
||||
}
|
||||
|
||||
RefPtr<ServiceWorkerUnregisterJob> mJob;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ServiceWorkerUnregisterJob::PushUnsubscribeCallback,
|
||||
nsIUnsubscribeResultCallback)
|
||||
|
||||
ServiceWorkerUnregisterJob::ServiceWorkerUnregisterJob(nsIPrincipal* aPrincipal,
|
||||
const nsACString& aScope,
|
||||
@ -41,6 +75,35 @@ ServiceWorkerUnregisterJob::AsyncExecute()
|
||||
return;
|
||||
}
|
||||
|
||||
// Push API, section 5: "When a service worker registration is unregistered,
|
||||
// any associated push subscription must be deactivated." To ensure the
|
||||
// service worker registration isn't cleared as we're unregistering, we
|
||||
// unsubscribe first.
|
||||
nsCOMPtr<nsIPushService> pushService =
|
||||
do_GetService("@mozilla.org/push/Service;1");
|
||||
if (NS_WARN_IF(!pushService)) {
|
||||
Unregister();
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIUnsubscribeResultCallback> unsubscribeCallback =
|
||||
new PushUnsubscribeCallback(this);
|
||||
nsresult rv = pushService->Unsubscribe(NS_ConvertUTF8toUTF16(mScope),
|
||||
mPrincipal, unsubscribeCallback);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
Unregister();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerUnregisterJob::Unregister()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (Canceled()) {
|
||||
Finish(NS_ERROR_DOM_ABORT_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 1 of the Unregister algorithm requires checking that the
|
||||
// client origin matches the scope's origin. We perform this in
|
||||
// registration->update() method directly since we don't have that
|
||||
|
@ -24,11 +24,16 @@ public:
|
||||
GetResult() const;
|
||||
|
||||
private:
|
||||
class PushUnsubscribeCallback;
|
||||
|
||||
virtual ~ServiceWorkerUnregisterJob();
|
||||
|
||||
virtual void
|
||||
AsyncExecute() override;
|
||||
|
||||
void
|
||||
Unregister();
|
||||
|
||||
bool mResult;
|
||||
bool mSendToParent;
|
||||
};
|
||||
|
@ -518,8 +518,10 @@ nsWindowWatcher::OpenWindowInternal(mozIDOMWindowProxy* aParent,
|
||||
nsCOMPtr<nsPIDOMWindowOuter> parent =
|
||||
aParent ? nsPIDOMWindowOuter::From(aParent) : nullptr;
|
||||
|
||||
MOZ_ASSERT_IF(openedFromRemoteTab,
|
||||
XRE_IsParentProcess());
|
||||
// When the opener is a remote tab, the url passed from the child process
|
||||
// isn't actually used. This code needs some serious refactoring.
|
||||
MOZ_ASSERT_IF(openedFromRemoteTab, !aUrl);
|
||||
MOZ_ASSERT_IF(openedFromRemoteTab, XRE_IsParentProcess());
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = 0;
|
||||
|
||||
|
@ -412,7 +412,7 @@ Compositor::IsValid() const
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
|
||||
void
|
||||
Compositor::SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget)
|
||||
Compositor::SetDispAcquireFence(Layer* aLayer)
|
||||
{
|
||||
// OpenGL does not provide ReleaseFence for rendering.
|
||||
// Instead use DispAcquireFence as layer buffer's ReleaseFence
|
||||
@ -420,11 +420,10 @@ Compositor::SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget)
|
||||
// DispAcquireFence is DisplaySurface's AcquireFence.
|
||||
// AcquireFence will be signaled when a buffer's content is available.
|
||||
// See Bug 974152.
|
||||
|
||||
if (!aLayer || !aWidget) {
|
||||
if (!aLayer || !mWidget) {
|
||||
return;
|
||||
}
|
||||
nsWindow* window = static_cast<nsWindow*>(aWidget);
|
||||
nsWindow* window = static_cast<nsWindow*>(mWidget->RealWidget());
|
||||
RefPtr<FenceHandle::FdObj> fence = new FenceHandle::FdObj(
|
||||
window->GetScreen()->GetPrevDispAcquireFd());
|
||||
mReleaseFenceHandle.Merge(FenceHandle(fence));
|
||||
@ -443,7 +442,7 @@ Compositor::GetReleaseFence()
|
||||
|
||||
#else
|
||||
void
|
||||
Compositor::SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget)
|
||||
Compositor::SetDispAcquireFence(Layer* aLayer)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -389,7 +389,7 @@ public:
|
||||
*/
|
||||
virtual void EndFrame() = 0;
|
||||
|
||||
virtual void SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget);
|
||||
virtual void SetDispAcquireFence(Layer* aLayer);
|
||||
|
||||
virtual FenceHandle GetReleaseFence();
|
||||
|
||||
@ -533,6 +533,9 @@ public:
|
||||
// frames and should not be used.
|
||||
void SetInvalid();
|
||||
bool IsValid() const;
|
||||
CompositorBridgeParent* GetCompositorBridgeParent() const {
|
||||
return mParent;
|
||||
}
|
||||
|
||||
protected:
|
||||
void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
|
||||
|
@ -781,6 +781,16 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
||||
return result;
|
||||
}
|
||||
|
||||
// If/when we enable support for pan inputs off-main-thread, we'll need
|
||||
// to duplicate this EventStateManager code or something. See the other
|
||||
// call to GetUserPrefsForWheelEvent in this file for why these fields
|
||||
// are stored separately.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
WidgetWheelEvent wheelEvent = panInput.ToWidgetWheelEvent(nullptr);
|
||||
EventStateManager::GetUserPrefsForWheelEvent(&wheelEvent,
|
||||
&panInput.mUserDeltaMultiplierX,
|
||||
&panInput.mUserDeltaMultiplierY);
|
||||
|
||||
RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(panInput.mPanStartPoint,
|
||||
&hitResult);
|
||||
if (apzc) {
|
||||
|
@ -1750,7 +1750,7 @@ AsyncPanZoomController::CanScroll(const InputData& aEvent) const
|
||||
delta = GetScrollWheelDelta(aEvent.AsScrollWheelInput());
|
||||
} else if (aEvent.mInputType == PANGESTURE_INPUT) {
|
||||
const PanGestureInput& panInput = aEvent.AsPanGestureInput();
|
||||
delta = ToParentLayerCoordinates(panInput.mPanDisplacement, panInput.mPanStartPoint);
|
||||
delta = ToParentLayerCoordinates(panInput.UserMultipliedPanDisplacement(), panInput.mPanStartPoint);
|
||||
}
|
||||
if (!delta.x && !delta.y) {
|
||||
return false;
|
||||
@ -2019,19 +2019,27 @@ nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent, bool
|
||||
return OnPanBegin(aEvent);
|
||||
}
|
||||
|
||||
// Note that there is a multiplier that applies onto the "physical" pan
|
||||
// displacement (how much the user's fingers moved) that produces the "logical"
|
||||
// pan displacement (how much the page should move). For some of the code
|
||||
// below it makes more sense to use the physical displacement rather than
|
||||
// the logical displacement, and vice-versa.
|
||||
ScreenPoint physicalPanDisplacement = aEvent.mPanDisplacement;
|
||||
ParentLayerPoint logicalPanDisplacement = aEvent.UserMultipliedLocalPanDisplacement();
|
||||
|
||||
// We need to update the axis velocity in order to get a useful display port
|
||||
// size and position. We need to do so even if this is a momentum pan (i.e.
|
||||
// aFingersOnTouchpad == false); in that case the "with touch" part is not
|
||||
// really appropriate, so we may want to rethink this at some point.
|
||||
mX.UpdateWithTouchAtDevicePoint(aEvent.mLocalPanStartPoint.x, aEvent.mLocalPanDisplacement.x, aEvent.mTime);
|
||||
mY.UpdateWithTouchAtDevicePoint(aEvent.mLocalPanStartPoint.y, aEvent.mLocalPanDisplacement.y, aEvent.mTime);
|
||||
mX.UpdateWithTouchAtDevicePoint(aEvent.mLocalPanStartPoint.x, logicalPanDisplacement.x, aEvent.mTime);
|
||||
mY.UpdateWithTouchAtDevicePoint(aEvent.mLocalPanStartPoint.y, logicalPanDisplacement.y, aEvent.mTime);
|
||||
|
||||
HandlePanningUpdate(aEvent.mPanDisplacement);
|
||||
HandlePanningUpdate(physicalPanDisplacement);
|
||||
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
|
||||
(uint32_t) ScrollInputMethod::ApzPanGesture);
|
||||
|
||||
ScreenPoint panDistance(fabs(aEvent.mPanDisplacement.x), fabs(aEvent.mPanDisplacement.y));
|
||||
ScreenPoint panDistance(fabs(physicalPanDisplacement.x), fabs(physicalPanDisplacement.y));
|
||||
OverscrollHandoffState handoffState(
|
||||
*CurrentPanGestureBlock()->GetOverscrollHandoffChain(),
|
||||
panDistance,
|
||||
@ -2045,7 +2053,7 @@ nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent, bool
|
||||
// the motion of the scrolled contents, not of the scroll position, they need
|
||||
// to move in the opposite direction of the pan displacement.
|
||||
ParentLayerPoint startPoint = aEvent.mLocalPanStartPoint;
|
||||
ParentLayerPoint endPoint = aEvent.mLocalPanStartPoint - aEvent.mLocalPanDisplacement;
|
||||
ParentLayerPoint endPoint = aEvent.mLocalPanStartPoint - logicalPanDisplacement;
|
||||
CallDispatchScroll(startPoint, endPoint, handoffState);
|
||||
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
|
@ -68,6 +68,7 @@
|
||||
#endif
|
||||
#include "GeckoProfiler.h"
|
||||
#include "TextRenderer.h" // for TextRenderer
|
||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||
|
||||
class gfxContext;
|
||||
|
||||
@ -944,7 +945,7 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi
|
||||
mCompositor->EndFrame();
|
||||
|
||||
// Call after EndFrame()
|
||||
mCompositor->SetDispAcquireFence(mRoot, mCompositor->GetWidget()->RealWidget());
|
||||
mCompositor->SetDispAcquireFence(mRoot);
|
||||
}
|
||||
|
||||
if (composer2D) {
|
||||
@ -1547,7 +1548,10 @@ LayerComposite::SetLayerManager(LayerManagerComposite* aManager)
|
||||
bool
|
||||
LayerManagerComposite::AsyncPanZoomEnabled() const
|
||||
{
|
||||
return mCompositor->GetWidget()->RealWidget()->AsyncPanZoomEnabled();
|
||||
if (CompositorBridgeParent* bridge = mCompositor->GetCompositorBridgeParent()) {
|
||||
return bridge->AsyncPanZoomEnabled();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIntRegion
|
||||
|
@ -305,12 +305,14 @@ CompositorVsyncScheduler::Observer::Destroy()
|
||||
mOwner = nullptr;
|
||||
}
|
||||
|
||||
CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent, nsIWidget* aWidget)
|
||||
CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent,
|
||||
widget::CompositorWidgetProxy* aWidgetProxy)
|
||||
: mCompositorBridgeParent(aCompositorBridgeParent)
|
||||
, mLastCompose(TimeStamp::Now())
|
||||
, mIsObservingVsync(false)
|
||||
, mNeedsComposite(0)
|
||||
, mVsyncNotificationsSkipped(0)
|
||||
, mCompositorVsyncDispatcher(aWidgetProxy->GetCompositorVsyncDispatcher())
|
||||
, mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
|
||||
, mCurrentCompositeTask(nullptr)
|
||||
, mSetNeedsCompositeMonitor("SetNeedsCompositeMonitor")
|
||||
@ -324,9 +326,7 @@ CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorBridgeParent* aComp
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aWidget != nullptr);
|
||||
mVsyncObserver = new Observer(this);
|
||||
mCompositorVsyncDispatcher = aWidget->GetCompositorVsyncDispatcher();
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
GeckoTouchDispatcher::GetInstance()->SetCompositorVsyncScheduler(this);
|
||||
|
||||
@ -348,7 +348,6 @@ CompositorVsyncScheduler::~CompositorVsyncScheduler()
|
||||
MOZ_ASSERT(!mVsyncObserver);
|
||||
// The CompositorVsyncDispatcher is cleaned up before this in the nsBaseWidget, which stops vsync listeners
|
||||
mCompositorBridgeParent = nullptr;
|
||||
mCompositorVsyncDispatcher = nullptr;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
@ -733,7 +732,7 @@ CompositorBridgeParent::CompositorBridgeParent(widget::CompositorWidgetProxy* aW
|
||||
mApzcTreeManager = new APZCTreeManager();
|
||||
}
|
||||
|
||||
mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget->RealWidget());
|
||||
mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget);
|
||||
LayerScope::SetPixelScale(aScale.scale);
|
||||
|
||||
// mSelfRef is cleared in DeferredDestroy.
|
||||
|
@ -110,7 +110,8 @@ class CompositorVsyncScheduler
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorVsyncScheduler)
|
||||
|
||||
public:
|
||||
explicit CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent, nsIWidget* aWidget);
|
||||
explicit CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent,
|
||||
widget::CompositorWidgetProxy* aWidgetProxy);
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// emulator-ics never trigger the display on/off, so compositor will always
|
||||
@ -516,6 +517,9 @@ public:
|
||||
dom::ContentParent* aContentParent,
|
||||
const dom::TabId& aTabId,
|
||||
dom::TabParent* aBrowserParent);
|
||||
bool AsyncPanZoomEnabled() const {
|
||||
return !!mApzcTreeManager;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Protected destructor, to discourage deletion outside of Release():
|
||||
|
@ -17,8 +17,8 @@ enum class FeatureStatus
|
||||
// This feature has not been requested.
|
||||
Unused,
|
||||
|
||||
// This feature is unavailable due to Safe Mode or not being included with
|
||||
// the operating system.
|
||||
// This feature is unavailable due to Safe Mode, not being included with
|
||||
// the operating system, or a dependent feature being disabled.
|
||||
Unavailable,
|
||||
|
||||
// This feature crashed immediately when we tried to initialize it, but we
|
||||
|
@ -1098,6 +1098,44 @@ gfxFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
||||
aSizes->mFontTableCacheSize +=
|
||||
mFontTableCache->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
// If the font has UVS data, we count that as part of the character map.
|
||||
if (mUVSData) {
|
||||
aSizes->mCharMapsSize += aMallocSizeOf(mUVSData.get());
|
||||
}
|
||||
|
||||
// The following, if present, are essentially cached forms of font table
|
||||
// data, so we'll accumulate them together with the basic table cache.
|
||||
if (mUserFontData) {
|
||||
aSizes->mFontTableCacheSize +=
|
||||
mUserFontData->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
if (mSVGGlyphs) {
|
||||
aSizes->mFontTableCacheSize +=
|
||||
mSVGGlyphs->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
if (mMathTable) {
|
||||
aSizes->mFontTableCacheSize +=
|
||||
mMathTable->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
if (mSupportedFeatures) {
|
||||
aSizes->mFontTableCacheSize +=
|
||||
mSupportedFeatures->ShallowSizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
if (mFeatureInputs) {
|
||||
aSizes->mFontTableCacheSize +=
|
||||
mFeatureInputs->ShallowSizeOfIncludingThis(aMallocSizeOf);
|
||||
for (auto iter = mFeatureInputs->ConstIter(); !iter.Done();
|
||||
iter.Next()) {
|
||||
// There's no API to get the real size of an hb_set, so we'll use
|
||||
// an approximation based on knowledge of the implementation.
|
||||
aSizes->mFontTableCacheSize += 8192; // vector of 64K bits
|
||||
}
|
||||
}
|
||||
// We don't include the size of mCOLR/mCPAL here, because (depending on the
|
||||
// font backend implementation) they will either wrap blocks of data owned
|
||||
// by the system (and potentially shared), or tables that are in our font
|
||||
// table cache and therefore already counted.
|
||||
}
|
||||
|
||||
void
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user