зеркало из https://github.com/mozilla/gecko-dev.git
merge autoland to mozilla-central a=merge
This commit is contained in:
Коммит
ebe55e2d67
|
@ -6,7 +6,7 @@ module.exports = {
|
|||
"mozilla"
|
||||
],
|
||||
"rules": {
|
||||
"mozilla/import-globals": 1,
|
||||
"mozilla/import-globals": "warn",
|
||||
},
|
||||
"env": {
|
||||
"es6": true
|
||||
|
|
|
@ -32,6 +32,30 @@ typedef [wire_marshal(mozHRGN)] void* HRGN;
|
|||
typedef [wire_marshal(mozHMONITOR)] void* HMONITOR;
|
||||
cpp_quote("#endif // 0")
|
||||
|
||||
import "Accessible2.idl";
|
||||
import "Accessible2_2.idl";
|
||||
import "Accessible2_3.idl";
|
||||
import "AccessibleAction.idl";
|
||||
import "AccessibleApplication.idl";
|
||||
import "AccessibleComponent.idl";
|
||||
import "AccessibleDocument.idl";
|
||||
import "AccessibleEditableText.idl";
|
||||
import "AccessibleEventId.idl";
|
||||
import "AccessibleHyperlink.idl";
|
||||
import "AccessibleHypertext.idl";
|
||||
import "AccessibleHypertext2.idl";
|
||||
import "AccessibleImage.idl";
|
||||
import "AccessibleRelation.idl";
|
||||
import "AccessibleRole.idl";
|
||||
import "AccessibleStates.idl";
|
||||
import "AccessibleTable.idl";
|
||||
import "AccessibleTable2.idl";
|
||||
import "AccessibleTableCell.idl";
|
||||
import "AccessibleText.idl";
|
||||
import "AccessibleText2.idl";
|
||||
import "AccessibleValue.idl";
|
||||
import "IA2CommonTypes.idl";
|
||||
|
||||
// We are explicitly using #include instead of import so that the imported
|
||||
// IDL is treated as part of this IDL file.
|
||||
#include "ia2_api_all.idl"
|
||||
#include "IA2TypeLibrary.idl"
|
||||
|
|
|
@ -51,168 +51,168 @@ module.exports = { // eslint-disable-line no-undef
|
|||
"findAccessibleChildByID": true
|
||||
},
|
||||
"rules": {
|
||||
"mozilla/no-aArgs": 1,
|
||||
"mozilla/no-cpows-in-tests": 1,
|
||||
"mozilla/reject-importGlobalProperties": 1,
|
||||
"mozilla/var-only-at-top-level": 1,
|
||||
"mozilla/no-aArgs": "warn",
|
||||
"mozilla/no-cpows-in-tests": "warn",
|
||||
"mozilla/reject-importGlobalProperties": "warn",
|
||||
"mozilla/var-only-at-top-level": "warn",
|
||||
|
||||
"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, 4],
|
||||
"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,
|
||||
"block-scoped-var": "error",
|
||||
"brace-style": ["error", "1tbs"],
|
||||
"camelcase": "error",
|
||||
"comma-dangle": ["error", "never"],
|
||||
"comma-spacing": "error",
|
||||
"comma-style": ["error", "last"],
|
||||
"complexity": ["error", 35],
|
||||
"consistent-this": "off",
|
||||
"curly": ["error", "multi-line"],
|
||||
"default-case": "off",
|
||||
"dot-location": ["error", "property"],
|
||||
"dot-notation": "error",
|
||||
"eol-last": "error",
|
||||
"eqeqeq": "off",
|
||||
"func-names": "off",
|
||||
"func-style": "off",
|
||||
"generator-star": "off",
|
||||
"global-strict": "off",
|
||||
"handle-callback-err": ["error", "er"],
|
||||
"indent": ["error", 2, {"SwitchCase": 1}],
|
||||
"key-spacing": ["error", {"beforeColon": false, "afterColon": true}],
|
||||
"linebreak-style": "off",
|
||||
"max-depth": "off",
|
||||
"max-nested-callbacks": ["error", 4],
|
||||
"max-params": "off",
|
||||
"max-statements": "off",
|
||||
"new-cap": ["error", {"capIsNew": false}],
|
||||
"new-parens": "error",
|
||||
"no-array-constructor": "error",
|
||||
"no-bitwise": "off",
|
||||
"no-caller": "error",
|
||||
"no-catch-shadow": "error",
|
||||
"no-comma-dangle": "off",
|
||||
"no-cond-assign": "error",
|
||||
"no-console": "off",
|
||||
"no-constant-condition": "off",
|
||||
"no-continue": "off",
|
||||
"no-control-regex": "error",
|
||||
"no-debugger": "error",
|
||||
"no-delete-var": "error",
|
||||
"no-div-regex": "off",
|
||||
"no-dupe-args": "error",
|
||||
"no-dupe-keys": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-else-return": "error",
|
||||
"no-empty": "error",
|
||||
"no-empty-character-class": "error",
|
||||
"no-eval": "error",
|
||||
"no-ex-assign": "error",
|
||||
"no-extend-native": "error",
|
||||
"no-extra-bind": "error",
|
||||
"no-extra-boolean-cast": "error",
|
||||
"no-extra-parens": "off",
|
||||
"no-extra-semi": "error",
|
||||
"no-extra-strict": "off",
|
||||
"no-fallthrough": "error",
|
||||
"no-floating-decimal": "off",
|
||||
"no-inline-comments": "off",
|
||||
"no-lonely-if": "error",
|
||||
"no-mixed-requires": "off",
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
"no-multi-spaces": "error",
|
||||
"no-multi-str": "error",
|
||||
"no-multiple-empty-lines": ["error", {"max": 1}],
|
||||
"no-native-reassign": "error",
|
||||
"no-nested-ternary": "error",
|
||||
"no-new-require": "off",
|
||||
"no-octal": "error",
|
||||
"no-param-reassign": "off",
|
||||
"no-path-concat": "off",
|
||||
"no-plusplus": "off",
|
||||
"no-process-env": "off",
|
||||
"no-process-exit": "off",
|
||||
"no-proto": "error",
|
||||
"no-redeclare": "error",
|
||||
"no-regex-spaces": "error",
|
||||
"no-reserved-keys": "off",
|
||||
"no-restricted-modules": "off",
|
||||
"no-return-assign": "warn",
|
||||
"no-script-url": "off",
|
||||
"no-self-compare": "error",
|
||||
"no-sequences": "error",
|
||||
"no-shadow": "warn",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-space-before-semi": "off",
|
||||
"no-spaced-func": "error",
|
||||
"no-sparse-arrays": "error",
|
||||
"no-sync": "off",
|
||||
"no-ternary": "off",
|
||||
"no-throw-literal": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-undef": "error",
|
||||
"no-underscore-dangle": "off",
|
||||
"no-undefined": "off",
|
||||
"no-unneeded-ternary": "error",
|
||||
"no-unreachable": "error",
|
||||
"no-unused-vars": ["error", {"vars": "all", "args": "none"}],
|
||||
"no-use-before-define": "off",
|
||||
"no-var": "off",
|
||||
"no-warning-comments": "off",
|
||||
"no-with": "error",
|
||||
"object-shorthand": "off",
|
||||
"one-var": ["error", "never"],
|
||||
"padded-blocks": ["error", "never"],
|
||||
"quote-props": "off",
|
||||
"radix": "error",
|
||||
"semi": ["error", "always"],
|
||||
"semi-spacing": ["error", {"before": false, "after": true}],
|
||||
"sort-vars": "off",
|
||||
"space-after-function-name": "off",
|
||||
"keyword-spacing": "error",
|
||||
"space-before-blocks": "error",
|
||||
"space-before-function-parentheses": "off",
|
||||
"space-before-function-paren": ["error", "never"],
|
||||
"space-in-brackets": "off",
|
||||
"space-in-parens": ["error", "never"],
|
||||
"space-infix-ops": ["error", {"int32Hint": true}],
|
||||
"space-unary-ops": ["error", { "words": true, "nonwords": false }],
|
||||
"space-unary-word-ops": "off",
|
||||
"spaced-comment": ["error", "always"],
|
||||
"strict": ["error", "global"],
|
||||
"use-isnan": "error",
|
||||
"valid-jsdoc": "off",
|
||||
"valid-typeof": "error",
|
||||
"vars-on-top": "off",
|
||||
"wrap-iife": "off",
|
||||
"wrap-regex": "off",
|
||||
"yoda": "error",
|
||||
|
||||
"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"]
|
||||
"guard-for-in": "off",
|
||||
"newline-after-var": "off",
|
||||
"no-alert": "off",
|
||||
"no-eq-null": "off",
|
||||
"no-func-assign": "off",
|
||||
"no-implied-eval": "off",
|
||||
"no-inner-declarations": "off",
|
||||
"no-invalid-regexp": "off",
|
||||
"no-irregular-whitespace": "off",
|
||||
"no-iterator": "off",
|
||||
"no-label-var": "off",
|
||||
"no-labels": "error",
|
||||
"no-lone-blocks": "off",
|
||||
"no-loop-func": "off",
|
||||
"no-negated-in-lhs": "off",
|
||||
"no-new": "off",
|
||||
"no-new-func": "off",
|
||||
"no-new-object": "off",
|
||||
"no-new-wrappers": "off",
|
||||
"no-obj-calls": "off",
|
||||
"no-octal-escape": "off",
|
||||
"no-undef-init": "error",
|
||||
"no-unexpected-multiline": "error",
|
||||
"object-curly-spacing": "off",
|
||||
"no-unused-expressions": "off",
|
||||
"no-void": "off",
|
||||
"no-wrap-func": "off",
|
||||
"operator-assignment": "off",
|
||||
"operator-linebreak": ["error", "after"]
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,6 +6,6 @@ module.exports = {
|
|||
],
|
||||
|
||||
"rules": {
|
||||
"no-undef": 2
|
||||
"no-undef": "error"
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,69 +14,69 @@ module.exports = { // eslint-disable-line no-undef
|
|||
"env": { "browser": true },
|
||||
|
||||
"rules": {
|
||||
"block-scoped-var": 2,
|
||||
// "brace-style": [1, "1tbs", {"allowSingleLine": true}],
|
||||
"comma-dangle": 0,
|
||||
"comma-spacing": [1, {"before": false, "after": true}],
|
||||
"comma-style": [1, "last"],
|
||||
// "complexity": 1,
|
||||
"consistent-return": 2,
|
||||
//"curly": 2,
|
||||
"dot-notation": 2,
|
||||
"eol-last": 2,
|
||||
"indent": [1, 2, {"SwitchCase": 1}],
|
||||
// "key-spacing": [1, {"beforeColon": false, "afterColon": true}],
|
||||
"keyword-spacing": 1,
|
||||
"max-nested-callbacks": [2, 3],
|
||||
"new-parens": 2,
|
||||
"no-array-constructor": 2,
|
||||
"no-cond-assign": 2,
|
||||
"no-control-regex": 2,
|
||||
"no-debugger": 2,
|
||||
"no-delete-var": 2,
|
||||
"no-dupe-args": 2,
|
||||
"no-dupe-keys": 2,
|
||||
"no-duplicate-case": 2,
|
||||
"no-else-return": 2,
|
||||
"no-eval": 2,
|
||||
"no-extend-native": 2,
|
||||
// "no-extra-bind": 2,
|
||||
"no-extra-boolean-cast": 2,
|
||||
"no-extra-semi": 1,
|
||||
"block-scoped-var": "error",
|
||||
// "brace-style": ["warn", "1tbs", {"allowSingleLine": true}],
|
||||
"comma-dangle": "off",
|
||||
"comma-spacing": ["warn", {"before": false, "after": true}],
|
||||
"comma-style": ["warn", "last"],
|
||||
// "complexity": "warn",
|
||||
"consistent-return": "error",
|
||||
//"curly": "error",
|
||||
"dot-notation": "error",
|
||||
"eol-last": "error",
|
||||
"indent": ["warn", 2, {"SwitchCase": 1}],
|
||||
// "key-spacing": ["warn", {"beforeColon": false, "afterColon": true}],
|
||||
"keyword-spacing": "warn",
|
||||
"max-nested-callbacks": ["error", 3],
|
||||
"new-parens": "error",
|
||||
"no-array-constructor": "error",
|
||||
"no-cond-assign": "error",
|
||||
"no-control-regex": "error",
|
||||
"no-debugger": "error",
|
||||
"no-delete-var": "error",
|
||||
"no-dupe-args": "error",
|
||||
"no-dupe-keys": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-else-return": "error",
|
||||
"no-eval": "error",
|
||||
"no-extend-native": "error",
|
||||
// "no-extra-bind": "error",
|
||||
"no-extra-boolean-cast": "error",
|
||||
"no-extra-semi": "warn",
|
||||
"no-fallthrough": ["error", { "commentPattern": ".*[Ii]ntentional(?:ly)?\\s+fall(?:ing)?[\\s-]*through.*" }],
|
||||
"no-lonely-if": 2,
|
||||
"no-mixed-spaces-and-tabs": 2,
|
||||
"no-multi-spaces": 1,
|
||||
"no-multi-str": 1,
|
||||
"no-native-reassign": 2,
|
||||
"no-nested-ternary": 2,
|
||||
"no-redeclare": 2,
|
||||
"no-return-assign": 2,
|
||||
"no-self-compare": 2,
|
||||
"no-sequences": 2,
|
||||
"no-shadow": 1,
|
||||
"no-shadow-restricted-names": 2,
|
||||
// "no-spaced-func": 1,
|
||||
"no-throw-literal": 2,
|
||||
"no-trailing-spaces": 2,
|
||||
"no-undef": 2,
|
||||
"no-unneeded-ternary": 2,
|
||||
"no-unreachable": 2,
|
||||
"no-lonely-if": "error",
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
"no-multi-spaces": "warn",
|
||||
"no-multi-str": "warn",
|
||||
"no-native-reassign": "error",
|
||||
"no-nested-ternary": "error",
|
||||
"no-redeclare": "error",
|
||||
"no-return-assign": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-sequences": "error",
|
||||
"no-shadow": "warn",
|
||||
"no-shadow-restricted-names": "error",
|
||||
// "no-spaced-func": "warn",
|
||||
"no-throw-literal": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-undef": "error",
|
||||
"no-unneeded-ternary": "error",
|
||||
"no-unreachable": "error",
|
||||
"no-unused-vars": ["error", { "varsIgnorePattern": "^C[ciur]$" }],
|
||||
"no-with": 2,
|
||||
"padded-blocks": [1, "never"],
|
||||
"no-with": "error",
|
||||
"padded-blocks": ["warn", "never"],
|
||||
"quotes": ["error", "double", { "avoidEscape": true, "allowTemplateLiterals": true }],
|
||||
"semi": [2, "always", {"omitLastInOneLineBlock": true }],
|
||||
"semi-spacing": [1, {"before": false, "after": true}],
|
||||
"space-before-blocks": [1, "always"],
|
||||
// "space-before-function-paren": [1, "never"],
|
||||
"space-in-parens": [1, "never"],
|
||||
"space-infix-ops": [1, {"int32Hint": true}],
|
||||
// "space-unary-ops": [1, { "words": true, "nonwords": false }],
|
||||
"strict": [2, "global"],
|
||||
"use-isnan": 2,
|
||||
"valid-typeof": 2,
|
||||
"yoda": 2
|
||||
"semi": ["error", "always", {"omitLastInOneLineBlock": true }],
|
||||
"semi-spacing": ["warn", {"before": false, "after": true}],
|
||||
"space-before-blocks": ["warn", "always"],
|
||||
// "space-before-function-paren": ["warn", "never"],
|
||||
"space-in-parens": ["warn", "never"],
|
||||
"space-infix-ops": ["warn", {"int32Hint": true}],
|
||||
// "space-unary-ops": ["warn", { "words": true, "nonwords": false }],
|
||||
"strict": ["error", "global"],
|
||||
"use-isnan": "error",
|
||||
"valid-typeof": "error",
|
||||
"yoda": "error"
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ const TEST_ENGINE_NAME = "Foo";
|
|||
const TEST_ENGINE_BASENAME = "testEngine.xml";
|
||||
const SEARCHBAR_BASE_ID = "searchbar-engine-one-off-item-";
|
||||
const URLBAR_BASE_ID = "urlbar-engine-one-off-item-";
|
||||
const ONEOFF_URLBAR_PREF = "browser.urlbar.oneOffSearches";
|
||||
|
||||
const searchbar = document.getElementById("searchbar");
|
||||
const urlbar = document.getElementById("urlbar");
|
||||
|
@ -60,6 +61,11 @@ add_task(function* test_searchBarChangeEngine() {
|
|||
});
|
||||
|
||||
add_task(function* test_urlBarChangeEngine() {
|
||||
Services.prefs.setBoolPref(ONEOFF_URLBAR_PREF, true);
|
||||
registerCleanupFunction(function* () {
|
||||
Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
|
||||
});
|
||||
|
||||
// Ensure the engine is reset.
|
||||
resetEngine();
|
||||
|
||||
|
|
|
@ -12,12 +12,12 @@ module.exports = { // eslint-disable-line no-undef
|
|||
|
||||
"rules": {
|
||||
// Rules from the mozilla plugin
|
||||
"mozilla/balanced-listeners": 2,
|
||||
"mozilla/no-aArgs": 1,
|
||||
"mozilla/no-cpows-in-tests": 1,
|
||||
"mozilla/var-only-at-top-level": 1,
|
||||
"mozilla/balanced-listeners": "error",
|
||||
"mozilla/no-aArgs": "warn",
|
||||
"mozilla/no-cpows-in-tests": "warn",
|
||||
"mozilla/var-only-at-top-level": "warn",
|
||||
|
||||
"valid-jsdoc": [2, {
|
||||
"valid-jsdoc": ["error", {
|
||||
"prefer": {
|
||||
"return": "returns",
|
||||
},
|
||||
|
@ -33,442 +33,442 @@ module.exports = { // eslint-disable-line no-undef
|
|||
}],
|
||||
|
||||
// Braces only needed for multi-line arrow function blocks
|
||||
// "arrow-body-style": [2, "as-needed"],
|
||||
// "arrow-body-style": ["error", "as-needed"],
|
||||
|
||||
// Require spacing around =>
|
||||
"arrow-spacing": 2,
|
||||
"arrow-spacing": "error",
|
||||
|
||||
// Always require spacing around a single line block
|
||||
"block-spacing": 1,
|
||||
"block-spacing": "warn",
|
||||
|
||||
// Forbid spaces inside the square brackets of array literals.
|
||||
"array-bracket-spacing": [2, "never"],
|
||||
"array-bracket-spacing": ["error", "never"],
|
||||
|
||||
// Forbid spaces inside the curly brackets of object literals.
|
||||
"object-curly-spacing": [2, "never"],
|
||||
"object-curly-spacing": ["error", "never"],
|
||||
|
||||
// No space padding in parentheses
|
||||
"space-in-parens": [2, "never"],
|
||||
"space-in-parens": ["error", "never"],
|
||||
|
||||
// Enforce one true brace style (opening brace on the same line) and avoid
|
||||
// start and end braces on the same line.
|
||||
"brace-style": [2, "1tbs", {"allowSingleLine": true}],
|
||||
"brace-style": ["error", "1tbs", {"allowSingleLine": true}],
|
||||
|
||||
// No space before always a space after a comma
|
||||
"comma-spacing": [2, {"before": false, "after": true}],
|
||||
"comma-spacing": ["error", {"before": false, "after": true}],
|
||||
|
||||
// Commas at the end of the line not the start
|
||||
"comma-style": 2,
|
||||
"comma-style": "error",
|
||||
|
||||
// Don't require spaces around computed properties
|
||||
"computed-property-spacing": [1, "never"],
|
||||
"computed-property-spacing": ["warn", "never"],
|
||||
|
||||
// Functions are not required to consistently return something or nothing
|
||||
"consistent-return": 0,
|
||||
"consistent-return": "off",
|
||||
|
||||
// Require braces around blocks that start a new line
|
||||
"curly": [2, "all"],
|
||||
"curly": ["error", "all"],
|
||||
|
||||
// Always require a trailing EOL
|
||||
"eol-last": 2,
|
||||
"eol-last": "error",
|
||||
|
||||
// Require function* name()
|
||||
"generator-star-spacing": [2, {"before": false, "after": true}],
|
||||
"generator-star-spacing": ["error", {"before": false, "after": true}],
|
||||
|
||||
// Two space indent
|
||||
"indent": [2, 2, {"SwitchCase": 1}],
|
||||
"indent": ["error", 2, {"SwitchCase": 1}],
|
||||
|
||||
// Space after colon not before in property declarations
|
||||
"key-spacing": [2, {"beforeColon": false, "afterColon": true, "mode": "minimum"}],
|
||||
"key-spacing": ["error", {"beforeColon": false, "afterColon": true, "mode": "minimum"}],
|
||||
|
||||
// Require spaces before and after finally, catch, etc.
|
||||
"keyword-spacing": 2,
|
||||
"keyword-spacing": "error",
|
||||
|
||||
// Unix linebreaks
|
||||
"linebreak-style": [2, "unix"],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
|
||||
// Always require parenthesis for new calls
|
||||
"new-parens": 2,
|
||||
"new-parens": "error",
|
||||
|
||||
// Use [] instead of Array()
|
||||
"no-array-constructor": 2,
|
||||
"no-array-constructor": "error",
|
||||
|
||||
// No duplicate arguments in function declarations
|
||||
"no-dupe-args": 2,
|
||||
"no-dupe-args": "error",
|
||||
|
||||
// No duplicate keys in object declarations
|
||||
"no-dupe-keys": 2,
|
||||
"no-dupe-keys": "error",
|
||||
|
||||
// No duplicate cases in switch statements
|
||||
"no-duplicate-case": 2,
|
||||
"no-duplicate-case": "error",
|
||||
|
||||
// If an if block ends with a return no need for an else block
|
||||
// "no-else-return": 2,
|
||||
// "no-else-return": "error",
|
||||
|
||||
// Disallow empty statements. This will report an error for:
|
||||
// try { something(); } catch (e) {}
|
||||
// but will not report it for:
|
||||
// try { something(); } catch (e) { /* Silencing the error because ...*/ }
|
||||
// which is a valid use case.
|
||||
"no-empty": 2,
|
||||
"no-empty": "error",
|
||||
|
||||
// No empty character classes in regex
|
||||
"no-empty-character-class": 2,
|
||||
"no-empty-character-class": "error",
|
||||
|
||||
// Disallow empty destructuring
|
||||
"no-empty-pattern": 2,
|
||||
"no-empty-pattern": "error",
|
||||
|
||||
// No assiging to exception variable
|
||||
"no-ex-assign": 2,
|
||||
"no-ex-assign": "error",
|
||||
|
||||
// No using !! where casting to boolean is already happening
|
||||
"no-extra-boolean-cast": 1,
|
||||
"no-extra-boolean-cast": "warn",
|
||||
|
||||
// No double semicolon
|
||||
"no-extra-semi": 2,
|
||||
"no-extra-semi": "error",
|
||||
|
||||
// No overwriting defined functions
|
||||
"no-func-assign": 2,
|
||||
"no-func-assign": "error",
|
||||
|
||||
// No invalid regular expresions
|
||||
"no-invalid-regexp": 2,
|
||||
"no-invalid-regexp": "error",
|
||||
|
||||
// No odd whitespace characters
|
||||
"no-irregular-whitespace": 2,
|
||||
"no-irregular-whitespace": "error",
|
||||
|
||||
// No single if block inside an else block
|
||||
"no-lonely-if": 1,
|
||||
"no-lonely-if": "warn",
|
||||
|
||||
// No mixing spaces and tabs in indent
|
||||
"no-mixed-spaces-and-tabs": [2, "smart-tabs"],
|
||||
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
|
||||
|
||||
// Disallow use of multiple spaces (sometimes used to align const values,
|
||||
// array or object items, etc.). It's hard to maintain and doesn't add that
|
||||
// much benefit.
|
||||
"no-multi-spaces": 1,
|
||||
"no-multi-spaces": "warn",
|
||||
|
||||
// No reassigning native JS objects
|
||||
"no-native-reassign": 2,
|
||||
"no-native-reassign": "error",
|
||||
|
||||
// No (!foo in bar)
|
||||
"no-negated-in-lhs": 2,
|
||||
"no-negated-in-lhs": "error",
|
||||
|
||||
// Nested ternary statements are confusing
|
||||
"no-nested-ternary": 2,
|
||||
"no-nested-ternary": "error",
|
||||
|
||||
// Use {} instead of new Object()
|
||||
"no-new-object": 2,
|
||||
"no-new-object": "error",
|
||||
|
||||
// No Math() or JSON()
|
||||
"no-obj-calls": 2,
|
||||
"no-obj-calls": "error",
|
||||
|
||||
// No octal literals
|
||||
"no-octal": 2,
|
||||
"no-octal": "error",
|
||||
|
||||
// No redeclaring variables
|
||||
"no-redeclare": 2,
|
||||
"no-redeclare": "error",
|
||||
|
||||
// No unnecessary comparisons
|
||||
"no-self-compare": 2,
|
||||
"no-self-compare": "error",
|
||||
|
||||
// No spaces between function name and parentheses
|
||||
"no-spaced-func": 1,
|
||||
"no-spaced-func": "warn",
|
||||
|
||||
// No trailing whitespace
|
||||
"no-trailing-spaces": 2,
|
||||
"no-trailing-spaces": "error",
|
||||
|
||||
// Error on newline where a semicolon is needed
|
||||
"no-unexpected-multiline": 2,
|
||||
"no-unexpected-multiline": "error",
|
||||
|
||||
// No unreachable statements
|
||||
"no-unreachable": 2,
|
||||
"no-unreachable": "error",
|
||||
|
||||
// No expressions where a statement is expected
|
||||
"no-unused-expressions": 2,
|
||||
"no-unused-expressions": "error",
|
||||
|
||||
// No declaring variables that are never used
|
||||
"no-unused-vars": [2, {"args": "none", "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$"}],
|
||||
"no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$"}],
|
||||
|
||||
// No using variables before defined
|
||||
"no-use-before-define": 2,
|
||||
"no-use-before-define": "error",
|
||||
|
||||
// No using with
|
||||
"no-with": 2,
|
||||
"no-with": "error",
|
||||
|
||||
// Always require semicolon at end of statement
|
||||
"semi": [2, "always"],
|
||||
"semi": ["error", "always"],
|
||||
|
||||
// Require space before blocks
|
||||
"space-before-blocks": 2,
|
||||
"space-before-blocks": "error",
|
||||
|
||||
// Never use spaces before function parentheses
|
||||
"space-before-function-paren": [2, {"anonymous": "never", "named": "never"}],
|
||||
"space-before-function-paren": ["error", {"anonymous": "never", "named": "never"}],
|
||||
|
||||
// Require spaces around operators, except for a|0.
|
||||
"space-infix-ops": [2, {"int32Hint": true}],
|
||||
// Require spaces around operators, except for a|"off".
|
||||
"space-infix-ops": ["error", {"int32Hint": true}],
|
||||
|
||||
// ++ and -- should not need spacing
|
||||
"space-unary-ops": [1, {"nonwords": false}],
|
||||
"space-unary-ops": ["warn", {"nonwords": false}],
|
||||
|
||||
// No comparisons to NaN
|
||||
"use-isnan": 2,
|
||||
"use-isnan": "error",
|
||||
|
||||
// Only check typeof against valid results
|
||||
"valid-typeof": 2,
|
||||
"valid-typeof": "error",
|
||||
|
||||
// Disallow using variables outside the blocks they are defined (especially
|
||||
// since only let and const are used, see "no-var").
|
||||
"block-scoped-var": 2,
|
||||
"block-scoped-var": "error",
|
||||
|
||||
// Allow trailing commas for easy list extension. Having them does not
|
||||
// impair readability, but also not required either.
|
||||
"comma-dangle": [2, "always-multiline"],
|
||||
"comma-dangle": ["error", "always-multiline"],
|
||||
|
||||
// Warn about cyclomatic complexity in functions.
|
||||
"complexity": 1,
|
||||
"complexity": "warn",
|
||||
|
||||
// Don't warn for inconsistent naming when capturing this (not so important
|
||||
// with auto-binding fat arrow functions).
|
||||
// "consistent-this": [2, "self"],
|
||||
// "consistent-this": ["error", "self"],
|
||||
|
||||
// Don't require a default case in switch statements. Avoid being forced to
|
||||
// add a bogus default when you know all possible cases are handled.
|
||||
"default-case": 0,
|
||||
"default-case": "off",
|
||||
|
||||
// Enforce dots on the next line with property name.
|
||||
"dot-location": [2, "property"],
|
||||
"dot-location": ["error", "property"],
|
||||
|
||||
// Encourage the use of dot notation whenever possible.
|
||||
"dot-notation": 2,
|
||||
"dot-notation": "error",
|
||||
|
||||
// Allow using == instead of ===, in the interest of landing something since
|
||||
// the devtools codebase is split on convention here.
|
||||
"eqeqeq": 0,
|
||||
"eqeqeq": "off",
|
||||
|
||||
// Don't require function expressions to have a name.
|
||||
// This makes the code more verbose and hard to read. Our engine already
|
||||
// does a fantastic job assigning a name to the function, which includes
|
||||
// the enclosing function name, and worst case you have a line number that
|
||||
// you can just look up.
|
||||
"func-names": 0,
|
||||
"func-names": "off",
|
||||
|
||||
// Allow use of function declarations and expressions.
|
||||
"func-style": 0,
|
||||
"func-style": "off",
|
||||
|
||||
// Don't enforce the maximum depth that blocks can be nested. The complexity
|
||||
// rule is a better rule to check this.
|
||||
"max-depth": 0,
|
||||
"max-depth": "off",
|
||||
|
||||
// Maximum length of a line.
|
||||
// Disabled because we exceed this in too many places.
|
||||
"max-len": [0, 80],
|
||||
"max-len": ["off", 80],
|
||||
|
||||
// Maximum depth callbacks can be nested.
|
||||
"max-nested-callbacks": [2, 4],
|
||||
"max-nested-callbacks": ["error", 4],
|
||||
|
||||
// Don't limit the number of parameters that can be used in a function.
|
||||
"max-params": 0,
|
||||
"max-params": "off",
|
||||
|
||||
// Don't limit the maximum number of statement allowed in a function. We
|
||||
// already have the complexity rule that's a better measurement.
|
||||
"max-statements": 0,
|
||||
"max-statements": "off",
|
||||
|
||||
// Don't require a capital letter for constructors, only check if all new
|
||||
// operators are followed by a capital letter. Don't warn when capitalized
|
||||
// functions are used without the new operator.
|
||||
"new-cap": [0, {"capIsNew": false}],
|
||||
"new-cap": ["off", {"capIsNew": false}],
|
||||
|
||||
// Allow use of bitwise operators.
|
||||
"no-bitwise": 0,
|
||||
"no-bitwise": "off",
|
||||
|
||||
// Disallow use of arguments.caller or arguments.callee.
|
||||
"no-caller": 2,
|
||||
"no-caller": "error",
|
||||
|
||||
// Disallow the catch clause parameter name being the same as a variable in
|
||||
// the outer scope, to avoid confusion.
|
||||
"no-catch-shadow": 0,
|
||||
"no-catch-shadow": "off",
|
||||
|
||||
// Disallow assignment in conditional expressions.
|
||||
"no-cond-assign": 2,
|
||||
"no-cond-assign": "error",
|
||||
|
||||
// Disallow using the console API.
|
||||
"no-console": 2,
|
||||
"no-console": "error",
|
||||
|
||||
// Allow using constant expressions in conditions like while (true)
|
||||
"no-constant-condition": 0,
|
||||
"no-constant-condition": "off",
|
||||
|
||||
// Allow use of the continue statement.
|
||||
"no-continue": 0,
|
||||
"no-continue": "off",
|
||||
|
||||
// Disallow control characters in regular expressions.
|
||||
"no-control-regex": 2,
|
||||
"no-control-regex": "error",
|
||||
|
||||
// Disallow use of debugger.
|
||||
"no-debugger": 2,
|
||||
"no-debugger": "error",
|
||||
|
||||
// Disallow deletion of variables (deleting properties is fine).
|
||||
"no-delete-var": 2,
|
||||
"no-delete-var": "error",
|
||||
|
||||
// Allow division operators explicitly at beginning of regular expression.
|
||||
"no-div-regex": 0,
|
||||
"no-div-regex": "off",
|
||||
|
||||
// Disallow use of eval(). We have other APIs to evaluate code in content.
|
||||
"no-eval": 2,
|
||||
"no-eval": "error",
|
||||
|
||||
// Disallow adding to native types
|
||||
"no-extend-native": 2,
|
||||
"no-extend-native": "error",
|
||||
|
||||
// Disallow unnecessary function binding.
|
||||
"no-extra-bind": 2,
|
||||
"no-extra-bind": "error",
|
||||
|
||||
// Allow unnecessary parentheses, as they may make the code more readable.
|
||||
"no-extra-parens": 0,
|
||||
"no-extra-parens": "off",
|
||||
|
||||
// Disallow fallthrough of case statements, except if there is a comment.
|
||||
"no-fallthrough": 2,
|
||||
"no-fallthrough": "error",
|
||||
|
||||
// Allow the use of leading or trailing decimal points in numeric literals.
|
||||
"no-floating-decimal": 0,
|
||||
"no-floating-decimal": "off",
|
||||
|
||||
// Allow comments inline after code.
|
||||
"no-inline-comments": 0,
|
||||
"no-inline-comments": "off",
|
||||
|
||||
// Disallow use of labels for anything other then loops and switches.
|
||||
"no-labels": [2, {"allowLoop": true}],
|
||||
"no-labels": ["error", {"allowLoop": true}],
|
||||
|
||||
// Disallow use of multiline strings (use template strings instead).
|
||||
"no-multi-str": 1,
|
||||
"no-multi-str": "warn",
|
||||
|
||||
// Disallow multiple empty lines.
|
||||
"no-multiple-empty-lines": [1, {"max": 2}],
|
||||
"no-multiple-empty-lines": ["warn", {"max": 2}],
|
||||
|
||||
// Allow reassignment of function parameters.
|
||||
"no-param-reassign": 0,
|
||||
"no-param-reassign": "off",
|
||||
|
||||
// Allow string concatenation with __dirname and __filename (not a node env).
|
||||
"no-path-concat": 0,
|
||||
"no-path-concat": "off",
|
||||
|
||||
// Allow use of unary operators, ++ and --.
|
||||
"no-plusplus": 0,
|
||||
"no-plusplus": "off",
|
||||
|
||||
// Allow using process.env (not a node environment).
|
||||
"no-process-env": 0,
|
||||
"no-process-env": "off",
|
||||
|
||||
// Allow using process.exit (not a node environment).
|
||||
"no-process-exit": 0,
|
||||
"no-process-exit": "off",
|
||||
|
||||
// Disallow usage of __proto__ property.
|
||||
"no-proto": 2,
|
||||
"no-proto": "error",
|
||||
|
||||
// Disallow multiple spaces in a regular expression literal.
|
||||
"no-regex-spaces": 2,
|
||||
"no-regex-spaces": "error",
|
||||
|
||||
// Allow reserved words being used as object literal keys.
|
||||
"no-reserved-keys": 0,
|
||||
"no-reserved-keys": "off",
|
||||
|
||||
// Don't restrict usage of specified node modules (not a node environment).
|
||||
"no-restricted-modules": 0,
|
||||
"no-restricted-modules": "off",
|
||||
|
||||
// Disallow use of assignment in return statement. It is preferable for a
|
||||
// single line of code to have only one easily predictable effect.
|
||||
"no-return-assign": 2,
|
||||
"no-return-assign": "error",
|
||||
|
||||
// Don't warn about declaration of variables already declared in the outer scope.
|
||||
"no-shadow": 0,
|
||||
"no-shadow": "off",
|
||||
|
||||
// Disallow shadowing of names such as arguments.
|
||||
"no-shadow-restricted-names": 2,
|
||||
"no-shadow-restricted-names": "error",
|
||||
|
||||
// Allow use of synchronous methods (not a node environment).
|
||||
"no-sync": 0,
|
||||
"no-sync": "off",
|
||||
|
||||
// Allow the use of ternary operators.
|
||||
"no-ternary": 0,
|
||||
"no-ternary": "off",
|
||||
|
||||
// Disallow throwing literals (eg. throw "error" instead of
|
||||
// throw new Error("error")).
|
||||
"no-throw-literal": 2,
|
||||
"no-throw-literal": "error",
|
||||
|
||||
// Disallow use of undeclared variables unless mentioned in a /* global */
|
||||
// block. Note that globals from head.js are automatically imported in tests
|
||||
// by the import-headjs-globals rule form the mozilla eslint plugin.
|
||||
"no-undef": 2,
|
||||
"no-undef": "error",
|
||||
|
||||
// Allow dangling underscores in identifiers (for privates).
|
||||
"no-underscore-dangle": 0,
|
||||
"no-underscore-dangle": "off",
|
||||
|
||||
// Allow use of undefined variable.
|
||||
"no-undefined": 0,
|
||||
"no-undefined": "off",
|
||||
|
||||
// Disallow the use of Boolean literals in conditional expressions.
|
||||
"no-unneeded-ternary": 2,
|
||||
"no-unneeded-ternary": "error",
|
||||
|
||||
// We use var-only-at-top-level instead of no-var as we allow top level
|
||||
// vars.
|
||||
"no-var": 0,
|
||||
"no-var": "off",
|
||||
|
||||
// Allow using TODO/FIXME comments.
|
||||
"no-warning-comments": 0,
|
||||
"no-warning-comments": "off",
|
||||
|
||||
// Don't require method and property shorthand syntax for object literals.
|
||||
// We use this in the code a lot, but not consistently, and this seems more
|
||||
// like something to check at code review time.
|
||||
"object-shorthand": 0,
|
||||
"object-shorthand": "off",
|
||||
|
||||
// Allow more than one variable declaration per function.
|
||||
"one-var": 0,
|
||||
"one-var": "off",
|
||||
|
||||
// Disallow padding within blocks.
|
||||
"padded-blocks": [1, "never"],
|
||||
"padded-blocks": ["warn", "never"],
|
||||
|
||||
// Don't require quotes around object literal property names.
|
||||
"quote-props": 0,
|
||||
"quote-props": "off",
|
||||
|
||||
// Double quotes should be used.
|
||||
"quotes": [1, "double", {"avoidEscape": true, "allowTemplateLiterals": true}],
|
||||
"quotes": ["warn", "double", {"avoidEscape": true, "allowTemplateLiterals": true}],
|
||||
|
||||
// Require use of the second argument for parseInt().
|
||||
"radix": 2,
|
||||
"radix": "error",
|
||||
|
||||
// Enforce spacing after semicolons.
|
||||
"semi-spacing": [2, {"before": false, "after": true}],
|
||||
"semi-spacing": ["error", {"before": false, "after": true}],
|
||||
|
||||
// Don't require to sort variables within the same declaration block.
|
||||
// Anyway, one-var is disabled.
|
||||
"sort-vars": 0,
|
||||
"sort-vars": "off",
|
||||
|
||||
// Require a space immediately following the // in a line comment.
|
||||
"spaced-comment": [2, "always"],
|
||||
"spaced-comment": ["error", "always"],
|
||||
|
||||
// Require "use strict" to be defined globally in the script.
|
||||
"strict": [2, "global"],
|
||||
"strict": ["error", "global"],
|
||||
|
||||
// Allow vars to be declared anywhere in the scope.
|
||||
"vars-on-top": 0,
|
||||
"vars-on-top": "off",
|
||||
|
||||
// Don't require immediate function invocation to be wrapped in parentheses.
|
||||
"wrap-iife": 0,
|
||||
"wrap-iife": "off",
|
||||
|
||||
// Don't require regex literals to be wrapped in parentheses (which
|
||||
// supposedly prevent them from being mistaken for division operators).
|
||||
"wrap-regex": 0,
|
||||
"wrap-regex": "off",
|
||||
|
||||
// Disallow Yoda conditions (where literal value comes first).
|
||||
"yoda": 2,
|
||||
"yoda": "error",
|
||||
|
||||
// disallow use of eval()-like methods
|
||||
"no-implied-eval": 2,
|
||||
"no-implied-eval": "error",
|
||||
|
||||
// Disallow function or variable declarations in nested blocks
|
||||
"no-inner-declarations": 2,
|
||||
"no-inner-declarations": "error",
|
||||
|
||||
// Disallow usage of __iterator__ property
|
||||
"no-iterator": 2,
|
||||
"no-iterator": "error",
|
||||
|
||||
// Disallow labels that share a name with a variable
|
||||
"no-label-var": 2,
|
||||
"no-label-var": "error",
|
||||
|
||||
// Disallow creating new instances of String, Number, and Boolean
|
||||
"no-new-wrappers": 2,
|
||||
"no-new-wrappers": "error",
|
||||
},
|
||||
};
|
||||
|
|
|
@ -412,7 +412,7 @@ Section "Uninstall"
|
|||
Delete /REBOOTOK "$INSTDIR\update-settings.ini"
|
||||
${EndIf}
|
||||
|
||||
; Explictly remove empty webapprt dir in case it exists (bug 757978).
|
||||
; Explicitly remove empty webapprt dir in case it exists (bug 757978).
|
||||
RmDir "$INSTDIR\webapprt\components"
|
||||
RmDir "$INSTDIR\webapprt"
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ const SCALAR_URLBAR = "browser.engagement.navigation.urlbar";
|
|||
const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
|
||||
// The name of the search engine used to generate suggestions.
|
||||
const SUGGESTION_ENGINE_NAME = "browser_UsageTelemetry usageTelemetrySearchSuggestions.xml";
|
||||
const ONEOFF_URLBAR_PREF = "browser.urlbar.oneOffSearches";
|
||||
|
||||
let searchInAwesomebar = Task.async(function* (inputText, win=window) {
|
||||
yield new Promise(r => waitForFocus(r, win));
|
||||
|
@ -55,11 +56,15 @@ add_task(function* setup() {
|
|||
// Enable search suggestions in the urlbar.
|
||||
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
|
||||
|
||||
// Enable the urlbar one-off buttons.
|
||||
Services.prefs.setBoolPref(ONEOFF_URLBAR_PREF, true);
|
||||
|
||||
// Make sure to restore the engine once we're done.
|
||||
registerCleanupFunction(function* () {
|
||||
Services.search.currentEngine = originalEngine;
|
||||
Services.search.removeEngine(engine);
|
||||
Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF, true);
|
||||
Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -37,28 +37,28 @@ module.exports = {
|
|||
// devtools coding style.
|
||||
|
||||
// Rules from the mozilla plugin
|
||||
"mozilla/no-aArgs": 1,
|
||||
"mozilla/no-cpows-in-tests": 2,
|
||||
"mozilla/no-single-arg-cu-import": 2,
|
||||
"mozilla/no-aArgs": "warn",
|
||||
"mozilla/no-cpows-in-tests": "error",
|
||||
"mozilla/no-single-arg-cu-import": "error",
|
||||
// See bug 1224289.
|
||||
"mozilla/reject-importGlobalProperties": 2,
|
||||
"mozilla/reject-importGlobalProperties": "error",
|
||||
// devtools/shared/platform is special; see the README.md in that
|
||||
// directory for details. We reject requires using explicit
|
||||
// subdirectories of this directory.
|
||||
"mozilla/reject-some-requires": [2, "^devtools/shared/platform/(chome|content)/"],
|
||||
"mozilla/var-only-at-top-level": 1,
|
||||
"mozilla/reject-some-requires": ["error", "^devtools/shared/platform/(chome|content)/"],
|
||||
"mozilla/var-only-at-top-level": "warn",
|
||||
|
||||
// Rules from the React plugin
|
||||
"react/display-name": 2,
|
||||
"react/no-danger": 2,
|
||||
"react/no-did-mount-set-state": 2,
|
||||
"react/no-did-update-set-state": 2,
|
||||
"react/no-direct-mutation-state": 2,
|
||||
"react/no-unknown-property": 2,
|
||||
"react/prefer-es6-class": [1, "never"],
|
||||
"react/display-name": "error",
|
||||
"react/no-danger": "error",
|
||||
"react/no-did-mount-set-state": "error",
|
||||
"react/no-did-update-set-state": "error",
|
||||
"react/no-direct-mutation-state": "error",
|
||||
"react/no-unknown-property": "error",
|
||||
"react/prefer-es6-class": ["warn", "never"],
|
||||
// Disabled temporarily until errors are fixed.
|
||||
"react/prop-types": 0,
|
||||
"react/sort-comp": [2, {
|
||||
"react/prop-types": "off",
|
||||
"react/sort-comp": ["error", {
|
||||
order: [
|
||||
"lifecycle",
|
||||
"everything-else",
|
||||
|
@ -91,382 +91,382 @@ module.exports = {
|
|||
|
||||
// Disallow using variables outside the blocks they are defined (especially
|
||||
// since only let and const are used, see "no-var").
|
||||
"block-scoped-var": 2,
|
||||
"block-scoped-var": "error",
|
||||
// Enforce one true brace style (opening brace on the same line) and avoid
|
||||
// start and end braces on the same line.
|
||||
"brace-style": [2, "1tbs", {"allowSingleLine": false}],
|
||||
"brace-style": ["error", "1tbs", {"allowSingleLine": false}],
|
||||
// Require camel case names
|
||||
"camelcase": 2,
|
||||
"camelcase": "error",
|
||||
// Allow trailing commas for easy list extension. Having them does not
|
||||
// impair readability, but also not required either.
|
||||
"comma-dangle": 0,
|
||||
"comma-dangle": "off",
|
||||
// Enforce spacing before and after comma
|
||||
"comma-spacing": [2, {"before": false, "after": true}],
|
||||
"comma-spacing": ["error", {"before": false, "after": true}],
|
||||
// Enforce one true comma style.
|
||||
"comma-style": [2, "last"],
|
||||
"comma-style": ["error", "last"],
|
||||
// Warn about cyclomatic complexity in functions.
|
||||
"complexity": [2, 35],
|
||||
"complexity": ["error", 35],
|
||||
// Require return statements to either always or never specify values.
|
||||
"consistent-return": 2,
|
||||
"consistent-return": "error",
|
||||
// Don't warn for inconsistent naming when capturing this (not so important
|
||||
// with auto-binding fat arrow functions).
|
||||
"consistent-this": 0,
|
||||
"consistent-this": "off",
|
||||
// Enforce curly brace conventions for all control statements.
|
||||
"curly": 2,
|
||||
"curly": "error",
|
||||
// Don't require a default case in switch statements. Avoid being forced to
|
||||
// add a bogus default when you know all possible cases are handled.
|
||||
"default-case": 0,
|
||||
"default-case": "off",
|
||||
// Enforce dots on the next line with property name.
|
||||
"dot-location": [2, "property"],
|
||||
"dot-location": ["error", "property"],
|
||||
// Encourage the use of dot notation whenever possible.
|
||||
"dot-notation": 2,
|
||||
"dot-notation": "error",
|
||||
// Enforce newline at the end of file, with no multiple empty lines.
|
||||
"eol-last": 2,
|
||||
"eol-last": "error",
|
||||
// Allow using == instead of ===, in the interest of landing something since
|
||||
// the devtools codebase is split on convention here.
|
||||
"eqeqeq": 0,
|
||||
"eqeqeq": "off",
|
||||
// Don't require function expressions to have a name.
|
||||
// This makes the code more verbose and hard to read. Our engine already
|
||||
// does a fantastic job assigning a name to the function, which includes
|
||||
// the enclosing function name, and worst case you have a line number that
|
||||
// you can just look up.
|
||||
"func-names": 0,
|
||||
"func-names": "off",
|
||||
// Allow use of function declarations and expressions.
|
||||
"func-style": 0,
|
||||
"func-style": "off",
|
||||
// Deprecated, will be removed in 1.0.
|
||||
"generator-star": 0,
|
||||
"generator-star": "off",
|
||||
// Enforce the spacing around the * in generator functions.
|
||||
"generator-star-spacing": [2, "after"],
|
||||
"generator-star-spacing": ["error", "after"],
|
||||
// Deprecated, will be removed in 1.0.
|
||||
"global-strict": 0,
|
||||
"global-strict": "off",
|
||||
// Only useful in a node environment.
|
||||
"handle-callback-err": 0,
|
||||
"handle-callback-err": "off",
|
||||
// Tab width.
|
||||
"indent": [2, 2, {"SwitchCase": 1}],
|
||||
"indent": ["error", 2, {"SwitchCase": 1}],
|
||||
// Enforces spacing between keys and values in object literal properties.
|
||||
"key-spacing": [2, {"beforeColon": false, "afterColon": true}],
|
||||
"key-spacing": ["error", {"beforeColon": false, "afterColon": true}],
|
||||
// Enforces unix style line breaks.
|
||||
"linebreak-style": [2, "unix"],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
// Don't enforce the maximum depth that blocks can be nested. The complexity
|
||||
// rule is a better rule to check this.
|
||||
"max-depth": 0,
|
||||
"max-depth": "off",
|
||||
// Maximum length of a line.
|
||||
"max-len": [2, 90, 2, {
|
||||
"max-len": ["error", 90, 2, {
|
||||
"ignoreUrls": true,
|
||||
"ignorePattern": "data:image\/|\\s*require\\s*\\(|^\\s*loader\\.lazy|-\\*-"
|
||||
}],
|
||||
// Maximum depth callbacks can be nested.
|
||||
"max-nested-callbacks": [2, 3],
|
||||
"max-nested-callbacks": ["error", 3],
|
||||
// Don't limit the number of parameters that can be used in a function.
|
||||
"max-params": 0,
|
||||
"max-params": "off",
|
||||
// Don't limit the maximum number of statement allowed in a function. We
|
||||
// already have the complexity rule that's a better measurement.
|
||||
"max-statements": 0,
|
||||
"max-statements": "off",
|
||||
// Require a capital letter for constructors, only check if all new
|
||||
// operators are followed by a capital letter. Don't warn when capitalized
|
||||
// functions are used without the new operator.
|
||||
"new-cap": [2, {"capIsNew": false}],
|
||||
"new-cap": ["error", {"capIsNew": false}],
|
||||
// Disallow the omission of parentheses when invoking a constructor with no
|
||||
// arguments.
|
||||
"new-parens": 2,
|
||||
"new-parens": "error",
|
||||
// Disallow use of the Array constructor.
|
||||
"no-array-constructor": 2,
|
||||
"no-array-constructor": "error",
|
||||
// Allow use of bitwise operators.
|
||||
"no-bitwise": 0,
|
||||
"no-bitwise": "off",
|
||||
// Disallow use of arguments.caller or arguments.callee.
|
||||
"no-caller": 2,
|
||||
"no-caller": "error",
|
||||
// Disallow the catch clause parameter name being the same as a variable in
|
||||
// the outer scope, to avoid confusion.
|
||||
"no-catch-shadow": 2,
|
||||
"no-catch-shadow": "error",
|
||||
// Deprecated, will be removed in 1.0.
|
||||
"no-comma-dangle": 0,
|
||||
"no-comma-dangle": "off",
|
||||
// Disallow assignment in conditional expressions.
|
||||
"no-cond-assign": 2,
|
||||
"no-cond-assign": "error",
|
||||
// Allow using the console API.
|
||||
"no-console": 0,
|
||||
"no-console": "off",
|
||||
// Allow using constant expressions in conditions like while (true)
|
||||
"no-constant-condition": 0,
|
||||
"no-constant-condition": "off",
|
||||
// Allow use of the continue statement.
|
||||
"no-continue": 0,
|
||||
"no-continue": "off",
|
||||
// Disallow control characters in regular expressions.
|
||||
"no-control-regex": 2,
|
||||
"no-control-regex": "error",
|
||||
// Disallow use of debugger.
|
||||
"no-debugger": 2,
|
||||
"no-debugger": "error",
|
||||
// Disallow deletion of variables (deleting properties is fine).
|
||||
"no-delete-var": 2,
|
||||
"no-delete-var": "error",
|
||||
// Allow division operators explicitly at beginning of regular expression.
|
||||
"no-div-regex": 0,
|
||||
"no-div-regex": "off",
|
||||
// Disallow duplicate arguments in functions.
|
||||
"no-dupe-args": 2,
|
||||
"no-dupe-args": "error",
|
||||
// Disallow duplicate keys when creating object literals.
|
||||
"no-dupe-keys": 2,
|
||||
"no-dupe-keys": "error",
|
||||
// Disallow a duplicate case label.
|
||||
"no-duplicate-case": 2,
|
||||
"no-duplicate-case": "error",
|
||||
// Disallow else after a return in an if. The else around the second return
|
||||
// here is useless:
|
||||
// if (something) { return false; } else { return true; }
|
||||
"no-else-return": 2,
|
||||
"no-else-return": "error",
|
||||
// Disallow empty statements. This will report an error for:
|
||||
// try { something(); } catch (e) {}
|
||||
// but will not report it for:
|
||||
// try { something(); } catch (e) { /* Silencing the error because ...*/ }
|
||||
// which is a valid use case.
|
||||
"no-empty": 2,
|
||||
"no-empty": "error",
|
||||
// Disallow the use of empty character classes in regular expressions.
|
||||
"no-empty-character-class": 2,
|
||||
"no-empty-character-class": "error",
|
||||
// Disallow use of eval(). We have other APIs to evaluate code in content.
|
||||
"no-eval": 2,
|
||||
"no-eval": "error",
|
||||
// Disallow assigning to the exception in a catch block.
|
||||
"no-ex-assign": 2,
|
||||
"no-ex-assign": "error",
|
||||
// Disallow adding to native types
|
||||
"no-extend-native": 2,
|
||||
"no-extend-native": "error",
|
||||
// Disallow unnecessary function binding.
|
||||
"no-extra-bind": 2,
|
||||
"no-extra-bind": "error",
|
||||
// Disallow double-negation boolean casts in a boolean context.
|
||||
"no-extra-boolean-cast": 2,
|
||||
"no-extra-boolean-cast": "error",
|
||||
// Allow unnecessary parentheses, as they may make the code more readable.
|
||||
"no-extra-parens": 0,
|
||||
"no-extra-parens": "off",
|
||||
// Disallow unnecessary semicolons.
|
||||
"no-extra-semi": 2,
|
||||
"no-extra-semi": "error",
|
||||
// Deprecated, will be removed in 1.0.
|
||||
"no-extra-strict": 0,
|
||||
"no-extra-strict": "off",
|
||||
// Disallow fallthrough of case statements, except if there is a comment.
|
||||
"no-fallthrough": 2,
|
||||
"no-fallthrough": "error",
|
||||
// Allow the use of leading or trailing decimal points in numeric literals.
|
||||
"no-floating-decimal": 0,
|
||||
"no-floating-decimal": "off",
|
||||
// Disallow comments inline after code.
|
||||
"no-inline-comments": 2,
|
||||
"no-inline-comments": "error",
|
||||
// Disallow if as the only statement in an else block.
|
||||
"no-lonely-if": 2,
|
||||
"no-lonely-if": "error",
|
||||
// Allow mixing regular variable and require declarations (not a node env).
|
||||
"no-mixed-requires": 0,
|
||||
"no-mixed-requires": "off",
|
||||
// Disallow mixed spaces and tabs for indentation.
|
||||
"no-mixed-spaces-and-tabs": 2,
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
// Disallow use of multiple spaces (sometimes used to align const values,
|
||||
// array or object items, etc.). It's hard to maintain and doesn't add that
|
||||
// much benefit.
|
||||
"no-multi-spaces": 2,
|
||||
"no-multi-spaces": "error",
|
||||
// Disallow use of multiline strings (use template strings instead).
|
||||
"no-multi-str": 2,
|
||||
"no-multi-str": "error",
|
||||
// Disallow multiple empty lines.
|
||||
"no-multiple-empty-lines": [2, {"max": 1}],
|
||||
"no-multiple-empty-lines": ["error", {"max": 1}],
|
||||
// Disallow reassignments of native objects.
|
||||
"no-native-reassign": 2,
|
||||
"no-native-reassign": "error",
|
||||
// Disallow nested ternary expressions, they make the code hard to read.
|
||||
"no-nested-ternary": 2,
|
||||
"no-nested-ternary": "error",
|
||||
// Allow use of new operator with the require function.
|
||||
"no-new-require": 0,
|
||||
"no-new-require": "off",
|
||||
// Disallow use of octal literals.
|
||||
"no-octal": 2,
|
||||
"no-octal": "error",
|
||||
// Allow reassignment of function parameters.
|
||||
"no-param-reassign": 0,
|
||||
"no-param-reassign": "off",
|
||||
// Allow string concatenation with __dirname and __filename (not a node env).
|
||||
"no-path-concat": 0,
|
||||
"no-path-concat": "off",
|
||||
// Allow use of unary operators, ++ and --.
|
||||
"no-plusplus": 0,
|
||||
"no-plusplus": "off",
|
||||
// Allow using process.env (not a node environment).
|
||||
"no-process-env": 0,
|
||||
"no-process-env": "off",
|
||||
// Allow using process.exit (not a node environment).
|
||||
"no-process-exit": 0,
|
||||
"no-process-exit": "off",
|
||||
// Disallow usage of __proto__ property.
|
||||
"no-proto": 2,
|
||||
"no-proto": "error",
|
||||
// Disallow declaring the same variable more than once (we use let anyway).
|
||||
"no-redeclare": 2,
|
||||
"no-redeclare": "error",
|
||||
// Disallow multiple spaces in a regular expression literal.
|
||||
"no-regex-spaces": 2,
|
||||
"no-regex-spaces": "error",
|
||||
// Allow reserved words being used as object literal keys.
|
||||
"no-reserved-keys": 0,
|
||||
"no-reserved-keys": "off",
|
||||
// Don't restrict usage of specified node modules (not a node environment).
|
||||
"no-restricted-modules": 0,
|
||||
"no-restricted-modules": "off",
|
||||
// Disallow use of assignment in return statement. It is preferable for a
|
||||
// single line of code to have only one easily predictable effect.
|
||||
"no-return-assign": 2,
|
||||
"no-return-assign": "error",
|
||||
// Allow use of javascript: urls.
|
||||
"no-script-url": 0,
|
||||
"no-script-url": "off",
|
||||
// Disallow comparisons where both sides are exactly the same.
|
||||
"no-self-compare": 2,
|
||||
"no-self-compare": "error",
|
||||
// Disallow use of comma operator.
|
||||
"no-sequences": 2,
|
||||
"no-sequences": "error",
|
||||
// Warn about declaration of variables already declared in the outer scope.
|
||||
// This isn't an error because it sometimes is useful to use the same name
|
||||
// in a small helper function rather than having to come up with another
|
||||
// random name.
|
||||
// Still, making this a warning can help people avoid being confused.
|
||||
"no-shadow": 2,
|
||||
"no-shadow": "error",
|
||||
// Disallow shadowing of names such as arguments.
|
||||
"no-shadow-restricted-names": 2,
|
||||
"no-shadow-restricted-names": "error",
|
||||
// Deprecated, will be removed in 1.0.
|
||||
"no-space-before-semi": 0,
|
||||
"no-space-before-semi": "off",
|
||||
// Disallow space between function identifier and application.
|
||||
"no-spaced-func": 2,
|
||||
"no-spaced-func": "error",
|
||||
// Disallow sparse arrays, eg. let arr = [,,2].
|
||||
// Array destructuring is fine though:
|
||||
// for (let [, breakpointPromise] of aPromises)
|
||||
"no-sparse-arrays": 2,
|
||||
"no-sparse-arrays": "error",
|
||||
// Allow use of synchronous methods (not a node environment).
|
||||
"no-sync": 0,
|
||||
"no-sync": "off",
|
||||
// Allow the use of ternary operators.
|
||||
"no-ternary": 0,
|
||||
"no-ternary": "off",
|
||||
// Disallow throwing literals (eg. throw "error" instead of
|
||||
// throw new Error("error")).
|
||||
"no-throw-literal": 2,
|
||||
"no-throw-literal": "error",
|
||||
// Disallow trailing whitespace at the end of lines.
|
||||
"no-trailing-spaces": 2,
|
||||
"no-trailing-spaces": "error",
|
||||
// Disallow use of undeclared variables unless mentioned in a /*global */
|
||||
// block. Note that globals from head.js are automatically imported in tests
|
||||
// by the import-headjs-globals rule form the mozilla eslint plugin.
|
||||
"no-undef": 2,
|
||||
"no-undef": "error",
|
||||
// Allow dangling underscores in identifiers (for privates).
|
||||
"no-underscore-dangle": 0,
|
||||
"no-underscore-dangle": "off",
|
||||
// Allow use of undefined variable.
|
||||
"no-undefined": 0,
|
||||
"no-undefined": "off",
|
||||
// Disallow the use of Boolean literals in conditional expressions.
|
||||
"no-unneeded-ternary": 2,
|
||||
"no-unneeded-ternary": "error",
|
||||
// Disallow unreachable statements after a return, throw, continue, or break
|
||||
// statement.
|
||||
"no-unreachable": 2,
|
||||
"no-unreachable": "error",
|
||||
// Disallow global and local variables that aren't used, but allow unused
|
||||
// function arguments.
|
||||
"no-unused-vars": [2, {"vars": "all", "args": "none"}],
|
||||
"no-unused-vars": ["error", {"vars": "all", "args": "none"}],
|
||||
// Allow using variables before they are defined.
|
||||
"no-use-before-define": 0,
|
||||
"no-use-before-define": "off",
|
||||
// We use var-only-at-top-level instead of no-var as we allow top level
|
||||
// vars.
|
||||
"no-var": 0,
|
||||
"no-var": "off",
|
||||
// Allow using TODO/FIXME comments.
|
||||
"no-warning-comments": 0,
|
||||
"no-warning-comments": "off",
|
||||
// Disallow use of the with statement.
|
||||
"no-with": 2,
|
||||
"no-with": "error",
|
||||
// Don't require method and property shorthand syntax for object literals.
|
||||
// We use this in the code a lot, but not consistently, and this seems more
|
||||
// like something to check at code review time.
|
||||
"object-shorthand": 0,
|
||||
"object-shorthand": "off",
|
||||
// Allow more than one variable declaration per function.
|
||||
"one-var": 0,
|
||||
"one-var": "off",
|
||||
// Disallow padding within blocks.
|
||||
"padded-blocks": [2, "never"],
|
||||
"padded-blocks": ["error", "never"],
|
||||
// Don't require quotes around object literal property names.
|
||||
"quote-props": 0,
|
||||
"quote-props": "off",
|
||||
// Double quotes should be used. Other quote characters can be used around strings
|
||||
// with embedded double quotes to avoid escaping them. Template literals are allowed
|
||||
// mainly for building multi-line messages where only some lines use substitution.
|
||||
"quotes": [2, "double", {"avoidEscape": true, "allowTemplateLiterals": true}],
|
||||
"quotes": ["error", "double", {"avoidEscape": true, "allowTemplateLiterals": true}],
|
||||
// Require use of the second argument for parseInt().
|
||||
"radix": 2,
|
||||
"radix": "error",
|
||||
// Always require use of semicolons wherever they are valid.
|
||||
"semi": [2, "always"],
|
||||
"semi": ["error", "always"],
|
||||
// Enforce spacing after semicolons.
|
||||
"semi-spacing": [2, {"before": false, "after": true}],
|
||||
"semi-spacing": ["error", {"before": false, "after": true}],
|
||||
// Don't require to sort variables within the same declaration block.
|
||||
// Anyway, one-var is disabled.
|
||||
"sort-vars": 0,
|
||||
"sort-vars": "off",
|
||||
// Deprecated, will be removed in 1.0.
|
||||
"space-after-function-name": 0,
|
||||
"space-after-function-name": "off",
|
||||
// Require a space around all keywords.
|
||||
"keyword-spacing": 2,
|
||||
"keyword-spacing": "error",
|
||||
// Require a space before the start brace of a block.
|
||||
"space-before-blocks": [2, "always"],
|
||||
"space-before-blocks": ["error", "always"],
|
||||
// Deprecated, will be removed in 1.0.
|
||||
"space-before-function-parentheses": 0,
|
||||
"space-before-function-parentheses": "off",
|
||||
// Require space after keyword for anonymous functions, but disallow space
|
||||
// after name of named functions.
|
||||
"space-before-function-paren": [2, {"anonymous": "always", "named": "never"}],
|
||||
"space-before-function-paren": ["error", {"anonymous": "always", "named": "never"}],
|
||||
// Disable the rule that checks if spaces inside {} and [] are there or not.
|
||||
// Our code is split on conventions, and it'd be nice to have 2 rules
|
||||
// Our code is split on conventions, and it'd be nice to have "error" rules
|
||||
// instead, one for [] and one for {}. So, disabling until we write them.
|
||||
"space-in-brackets": 0,
|
||||
"space-in-brackets": "off",
|
||||
// Disallow spaces inside parentheses.
|
||||
"space-in-parens": [2, "never"],
|
||||
// Require spaces around operators, except for a|0.
|
||||
"space-infix-ops": [2, {"int32Hint": true}],
|
||||
"space-in-parens": ["error", "never"],
|
||||
// Require spaces around operators, except for a|"off".
|
||||
"space-infix-ops": ["error", {"int32Hint": true}],
|
||||
// Require spaces before/after unary operators (words on by default,
|
||||
// nonwords off by default).
|
||||
"space-unary-ops": [2, { "words": true, "nonwords": false }],
|
||||
"space-unary-ops": ["error", { "words": true, "nonwords": false }],
|
||||
// Deprecated, will be removed in 1.0.
|
||||
"space-unary-word-ops": 0,
|
||||
"space-unary-word-ops": "off",
|
||||
// Require a space immediately following the // in a line comment.
|
||||
"spaced-comment": [2, "always"],
|
||||
"spaced-comment": ["error", "always"],
|
||||
// Require "use strict" to be defined globally in the script.
|
||||
"strict": [2, "global"],
|
||||
"strict": ["error", "global"],
|
||||
// Disallow comparisons with the value NaN.
|
||||
"use-isnan": 2,
|
||||
"use-isnan": "error",
|
||||
// Warn about invalid JSDoc comments.
|
||||
// Disabled for now because of https://github.com/eslint/eslint/issues/2270
|
||||
// The rule fails on some jsdoc comments like in:
|
||||
// devtools/client/webconsole/console-output.js
|
||||
"valid-jsdoc": 0,
|
||||
"valid-jsdoc": "off",
|
||||
// Ensure that the results of typeof are compared against a valid string.
|
||||
"valid-typeof": 2,
|
||||
"valid-typeof": "error",
|
||||
// Allow vars to be declared anywhere in the scope.
|
||||
"vars-on-top": 0,
|
||||
"vars-on-top": "off",
|
||||
// Don't require immediate function invocation to be wrapped in parentheses.
|
||||
"wrap-iife": 0,
|
||||
"wrap-iife": "off",
|
||||
// Don't require regex literals to be wrapped in parentheses (which
|
||||
// supposedly prevent them from being mistaken for division operators).
|
||||
"wrap-regex": 0,
|
||||
"wrap-regex": "off",
|
||||
// Disallow Yoda conditions (where literal value comes first).
|
||||
"yoda": 2,
|
||||
"yoda": "error",
|
||||
|
||||
// And these are the rules that haven't been discussed so far, and that are
|
||||
// disabled for now until we introduce them, one at a time.
|
||||
|
||||
// Require for-in loops to have an if statement.
|
||||
"guard-for-in": 0,
|
||||
"guard-for-in": "off",
|
||||
// allow/disallow an empty newline after var statement
|
||||
"newline-after-var": 0,
|
||||
"newline-after-var": "off",
|
||||
// disallow the use of alert, confirm, and prompt
|
||||
"no-alert": 0,
|
||||
"no-alert": "off",
|
||||
// disallow comparisons to null without a type-checking operator
|
||||
"no-eq-null": 0,
|
||||
"no-eq-null": "off",
|
||||
// disallow overwriting functions written as function declarations
|
||||
"no-func-assign": 0,
|
||||
"no-func-assign": "off",
|
||||
// disallow use of eval()-like methods
|
||||
"no-implied-eval": 0,
|
||||
"no-implied-eval": "off",
|
||||
// disallow function or variable declarations in nested blocks
|
||||
"no-inner-declarations": 0,
|
||||
"no-inner-declarations": "off",
|
||||
// disallow invalid regular expression strings in the RegExp constructor
|
||||
"no-invalid-regexp": 0,
|
||||
"no-invalid-regexp": "off",
|
||||
// disallow irregular whitespace outside of strings and comments
|
||||
"no-irregular-whitespace": 0,
|
||||
"no-irregular-whitespace": "off",
|
||||
// disallow usage of __iterator__ property
|
||||
"no-iterator": 0,
|
||||
"no-iterator": "off",
|
||||
// disallow labels that share a name with a variable
|
||||
"no-label-var": 0,
|
||||
"no-label-var": "off",
|
||||
// disallow use of labeled statements
|
||||
"no-labels": 2,
|
||||
"no-labels": "error",
|
||||
// disallow unnecessary nested blocks
|
||||
"no-lone-blocks": 0,
|
||||
"no-lone-blocks": "off",
|
||||
// disallow creation of functions within loops
|
||||
"no-loop-func": 0,
|
||||
"no-loop-func": "off",
|
||||
// disallow negation of the left operand of an in expression
|
||||
"no-negated-in-lhs": 0,
|
||||
"no-negated-in-lhs": "off",
|
||||
// disallow use of new operator when not part of the assignment or
|
||||
// comparison
|
||||
"no-new": 0,
|
||||
"no-new": "off",
|
||||
// disallow use of new operator for Function object
|
||||
"no-new-func": 0,
|
||||
"no-new-func": "off",
|
||||
// disallow use of the Object constructor
|
||||
"no-new-object": 0,
|
||||
"no-new-object": "off",
|
||||
// disallows creating new instances of String,Number, and Boolean
|
||||
"no-new-wrappers": 0,
|
||||
"no-new-wrappers": "off",
|
||||
// disallow the use of object properties of the global object (Math and
|
||||
// JSON) as functions
|
||||
"no-obj-calls": 0,
|
||||
"no-obj-calls": "off",
|
||||
// disallow use of octal escape sequences in string literals, such as
|
||||
// var foo = "Copyright \251";
|
||||
"no-octal-escape": 0,
|
||||
"no-octal-escape": "off",
|
||||
// disallow use of undefined when initializing variables
|
||||
"no-undef-init": 0,
|
||||
"no-undef-init": "off",
|
||||
// disallow usage of expressions in statement position
|
||||
"no-unused-expressions": 0,
|
||||
"no-unused-expressions": "off",
|
||||
// disallow use of void operator
|
||||
"no-void": 0,
|
||||
"no-void": "off",
|
||||
// disallow wrapping of non-IIFE statements in parens
|
||||
"no-wrap-func": 0,
|
||||
"no-wrap-func": "off",
|
||||
// require assignment operator shorthand where possible or prohibit it
|
||||
// entirely
|
||||
"operator-assignment": 0,
|
||||
"operator-assignment": "off",
|
||||
// enforce operators to be placed before or after line breaks
|
||||
"operator-linebreak": 0,
|
||||
"operator-linebreak": "off",
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ module.exports = {
|
|||
"MessageEvent": true
|
||||
},
|
||||
"rules": {
|
||||
"indent": 0,
|
||||
"padded-blocks": 0,
|
||||
"indent": "off",
|
||||
"padded-blocks": "off",
|
||||
}
|
||||
};
|
||||
|
|
|
@ -10,6 +10,6 @@ module.exports = {
|
|||
// code. Some files in the inspector disable this rule still. The
|
||||
// goal is to enable the rule globally on all files.
|
||||
/* eslint-disable max-len */
|
||||
"mozilla/reject-some-requires": [2, "^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm|devtools/shared/platform/(chome|content)/.*)$"],
|
||||
"mozilla/reject-some-requires": ["error", "^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm|devtools/shared/platform/(chome|content)/.*)$"],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -10,6 +10,6 @@ module.exports = {
|
|||
// code. Some files in the netmonitor disable this rule still. The
|
||||
// goal is to enable the rule globally on all files.
|
||||
/* eslint-disable max-len */
|
||||
"mozilla/reject-some-requires": [2, "^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm|devtools/shared/platform/(chome|content)/.*)$"],
|
||||
"mozilla/reject-some-requires": ["error", "^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm|devtools/shared/platform/(chome|content)/.*)$"],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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";
|
||||
|
||||
// Make this available to both AMD and CJS environments
|
||||
define(function (require, exports, module) {
|
||||
// Dependencies
|
||||
const React = require("devtools/client/shared/vendor/react");
|
||||
const { sanitizeString, isGrip } = require("./rep-utils");
|
||||
// Shortcuts
|
||||
const { span } = React.DOM;
|
||||
|
||||
/**
|
||||
* Renders a long string grip.
|
||||
*/
|
||||
const LongStringRep = React.createClass({
|
||||
displayName: "LongStringRep",
|
||||
|
||||
propTypes: {
|
||||
useQuotes: React.PropTypes.bool,
|
||||
style: React.PropTypes.object,
|
||||
},
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
useQuotes: true,
|
||||
};
|
||||
},
|
||||
|
||||
render: function () {
|
||||
let {
|
||||
cropLimit,
|
||||
member,
|
||||
object,
|
||||
style,
|
||||
useQuotes
|
||||
} = this.props;
|
||||
let {fullText, initial, length} = object;
|
||||
|
||||
let config = {className: "objectBox objectBox-string"};
|
||||
if (style) {
|
||||
config.style = style;
|
||||
}
|
||||
|
||||
let string = member && member.open
|
||||
? fullText || initial
|
||||
: initial.substring(0, cropLimit);
|
||||
|
||||
if (string.length < length) {
|
||||
string += "\u2026";
|
||||
}
|
||||
let formattedString = useQuotes ? `"${string}"` : string;
|
||||
return span(config, sanitizeString(formattedString));
|
||||
},
|
||||
});
|
||||
|
||||
function supportsObject(object, type) {
|
||||
if (!isGrip(object)) {
|
||||
return false;
|
||||
}
|
||||
return object.type === "longString";
|
||||
}
|
||||
|
||||
// Exports from this module
|
||||
exports.LongStringRep = {
|
||||
rep: LongStringRep,
|
||||
supportsObject: supportsObject,
|
||||
};
|
||||
});
|
|
@ -18,6 +18,7 @@ DevToolsModules(
|
|||
'grip-map.js',
|
||||
'grip.js',
|
||||
'infinity.js',
|
||||
'long-string.js',
|
||||
'nan.js',
|
||||
'null.js',
|
||||
'number.js',
|
||||
|
|
|
@ -45,15 +45,8 @@ define(function (require, exports, module) {
|
|||
alternativeText = "\u2026";
|
||||
}
|
||||
|
||||
// Make sure it's a string.
|
||||
text = text + "";
|
||||
|
||||
// Replace all non-printable characters, except of
|
||||
// (horizontal) tab (HT: \x09) and newline (LF: \x0A, CR: \x0D),
|
||||
// with unicode replacement character (u+fffd).
|
||||
// eslint-disable-next-line no-control-regex
|
||||
let re = new RegExp("[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\x9F]", "g");
|
||||
text = text.replace(re, "\ufffd");
|
||||
// Make sure it's a string and sanitize it.
|
||||
text = sanitizeString(text + "");
|
||||
|
||||
// Crop the string only if a limit is actually specified.
|
||||
if (!limit || limit <= 0) {
|
||||
|
@ -76,6 +69,15 @@ define(function (require, exports, module) {
|
|||
return text;
|
||||
}
|
||||
|
||||
function sanitizeString(text) {
|
||||
// Replace all non-printable characters, except of
|
||||
// (horizontal) tab (HT: \x09) and newline (LF: \x0A, CR: \x0D),
|
||||
// with unicode replacement character (u+fffd).
|
||||
// eslint-disable-next-line no-control-regex
|
||||
let re = new RegExp("[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\x9F]", "g");
|
||||
return text.replace(re, "\ufffd");
|
||||
}
|
||||
|
||||
function parseURLParams(url) {
|
||||
url = new URL(url);
|
||||
return parseURLEncodedText(url.searchParams);
|
||||
|
@ -154,4 +156,5 @@ define(function (require, exports, module) {
|
|||
exports.parseURLEncodedText = parseURLEncodedText;
|
||||
exports.getFileName = getFileName;
|
||||
exports.getURLDisplayString = getURLDisplayString;
|
||||
exports.sanitizeString = sanitizeString;
|
||||
});
|
||||
|
|
|
@ -17,6 +17,7 @@ define(function (require, exports, module) {
|
|||
const { Undefined } = require("./undefined");
|
||||
const { Null } = require("./null");
|
||||
const { StringRep } = require("./string");
|
||||
const { LongStringRep } = require("./long-string");
|
||||
const { Number } = require("./number");
|
||||
const { ArrayRep } = require("./array");
|
||||
const { Obj } = require("./object");
|
||||
|
@ -55,6 +56,7 @@ define(function (require, exports, module) {
|
|||
ElementNode,
|
||||
TextNode,
|
||||
Attribute,
|
||||
LongStringRep,
|
||||
Func,
|
||||
PromiseRep,
|
||||
ArrayRep,
|
||||
|
|
|
@ -19,6 +19,7 @@ support-files =
|
|||
[test_reps_grip-array.html]
|
||||
[test_reps_grip-map.html]
|
||||
[test_reps_infinity.html]
|
||||
[test_reps_long-string.html]
|
||||
[test_reps_nan.html]
|
||||
[test_reps_null.html]
|
||||
[test_reps_number.html]
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
<!-- 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/. -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Test LongString rep
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Rep test - LongString</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script src="head.js" type="application/javascript;version=1.8"></script>
|
||||
<script type="application/javascript;version=1.8">
|
||||
window.onload = Task.async(function* () {
|
||||
let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
|
||||
let { LongStringRep } = browserRequire("devtools/client/shared/components/reps/long-string");
|
||||
|
||||
try {
|
||||
// Test that correct rep is chosen
|
||||
const renderedRep = shallowRenderComponent(Rep, { object: getGripStub("testMultiline") });
|
||||
is(renderedRep.type, LongStringRep.rep,
|
||||
`Rep correctly selects ${LongStringRep.rep.displayName}`);
|
||||
|
||||
// Test rendering
|
||||
yield testMultiline();
|
||||
yield testMultilineOpen();
|
||||
yield testFullText();
|
||||
yield testMultilineLimit();
|
||||
yield testUseQuotes();
|
||||
} catch (e) {
|
||||
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
|
||||
} finally {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function testMultiline() {
|
||||
const stub = getGripStub("testMultiline");
|
||||
const renderedComponent = renderComponent(
|
||||
LongStringRep.rep, { object: stub });
|
||||
|
||||
is(renderedComponent.textContent, `"${stub.initial}…"`,
|
||||
"LongString rep has expected text content for multiline string");
|
||||
}
|
||||
|
||||
function testMultilineLimit() {
|
||||
const renderedComponent = renderComponent(
|
||||
LongStringRep.rep, { object: getGripStub("testMultiline"), cropLimit: 20 });
|
||||
|
||||
is(
|
||||
renderedComponent.textContent,
|
||||
`"a\naaaaaaaaaaaaaaaaaa…"`,
|
||||
"LongString rep has expected text content for multiline string " +
|
||||
"with specified number of characters");
|
||||
}
|
||||
|
||||
function testMultilineOpen() {
|
||||
const stub = getGripStub("testMultiline");
|
||||
const renderedComponent = renderComponent(
|
||||
LongStringRep.rep, { object: stub, member: {open: true}, cropLimit: 20 });
|
||||
|
||||
is(renderedComponent.textContent, `"${stub.initial}…"`,
|
||||
"LongString rep has expected text content for multiline string when open");
|
||||
}
|
||||
|
||||
function testFullText() {
|
||||
const stub = getGripStub("testFullText");
|
||||
const renderedComponentOpen = renderComponent(
|
||||
LongStringRep.rep, { object: stub, member: {open: true}, cropLimit: 20 });
|
||||
|
||||
is(renderedComponentOpen.textContent, `"${stub.fullText}"`,
|
||||
"LongString rep has expected text content when grip has a fullText " +
|
||||
"property and is open");
|
||||
|
||||
const renderedComponentNotOpen = renderComponent(
|
||||
LongStringRep.rep, { object: stub, cropLimit: 20 });
|
||||
|
||||
is(renderedComponentNotOpen.textContent,
|
||||
`"a\naaaaaaaaaaaaaaaaaa…"`,
|
||||
"LongString rep has expected text content when grip has a fullText " +
|
||||
"property and is not open");
|
||||
}
|
||||
|
||||
function testUseQuotes() {
|
||||
const renderedComponent = renderComponent(LongStringRep.rep,
|
||||
{ object: getGripStub("testMultiline"), cropLimit: 20, useQuotes: false });
|
||||
|
||||
is(renderedComponent.textContent,
|
||||
"a\naaaaaaaaaaaaaaaaaa…",
|
||||
"LongString rep was expected to omit quotes");
|
||||
}
|
||||
|
||||
function getGripStub(name) {
|
||||
const multilineFullText = "a\n" + Array(20000).fill("a").join("");
|
||||
const fullTextLength = multilineFullText.length;
|
||||
const initialText = multilineFullText.substring(0, 10000);
|
||||
|
||||
switch (name) {
|
||||
case "testMultiline":
|
||||
return {
|
||||
"type": "longString",
|
||||
"initial": initialText,
|
||||
"length": fullTextLength,
|
||||
"actor": "server1.conn1.child1/longString58"
|
||||
};
|
||||
case "testFullText":
|
||||
return {
|
||||
"type": "longString",
|
||||
"fullText": multilineFullText,
|
||||
"initial": initialText,
|
||||
"length": fullTextLength,
|
||||
"actor": "server1.conn1.child1/longString58"
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -10,6 +10,6 @@ module.exports = {
|
|||
// code. Some files here disable this rule still. The
|
||||
// goal is to enable the rule globally on all files.
|
||||
/* eslint-disable max-len */
|
||||
"mozilla/reject-some-requires": [2, "^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm)$"],
|
||||
"mozilla/reject-some-requires": ["error", "^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm)$"],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -15,6 +15,6 @@ module.exports = {
|
|||
"setTimeout": true
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": [2, {"args": "none"}],
|
||||
"no-unused-vars": ["error", {"args": "none"}],
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,6 @@ module.exports = {
|
|||
"rules": {
|
||||
/* eslint-disable max-len */
|
||||
// All code in this directory must be content-clean.
|
||||
"mozilla/reject-some-requires": [2, "^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm|devtools/shared/platform/(chome|content)/.*)$"],
|
||||
"mozilla/reject-some-requires": ["error", "^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm|devtools/shared/platform/(chome|content)/.*)$"],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -14247,6 +14247,20 @@ nsDocShell::GetIsInMozBrowserOrApp(bool* aIsInMozBrowserOrApp)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* [infallible] */ NS_IMETHODIMP
|
||||
nsDocShell::GetIsTopLevelContentDocShell(bool* aIsTopLevelContentDocShell)
|
||||
{
|
||||
*aIsTopLevelContentDocShell = false;
|
||||
|
||||
if (mItemType == typeContent) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> root;
|
||||
GetSameTypeRootTreeItem(getter_AddRefs(root));
|
||||
*aIsTopLevelContentDocShell = root.get() == static_cast<nsIDocShellTreeItem*>(this);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* [infallible] */ NS_IMETHODIMP
|
||||
nsDocShell::GetAppId(uint32_t* aAppId)
|
||||
{
|
||||
|
|
|
@ -851,6 +851,11 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||
*/
|
||||
[infallible] readonly attribute boolean isInMozBrowserOrApp;
|
||||
|
||||
/**
|
||||
* Returns true if this docshell is the top level content docshell.
|
||||
*/
|
||||
[infallible] readonly attribute boolean isTopLevelContentDocShell;
|
||||
|
||||
/**
|
||||
* Returns the id of the app associated with this docshell. If this docshell
|
||||
* is an <iframe mozbrowser> inside an <iframe mozapp>, we return the app's
|
||||
|
|
|
@ -257,6 +257,20 @@ var tests = [
|
|||
is(xhr.responseText, "a3", "We got the expected file body");
|
||||
},
|
||||
},
|
||||
|
||||
// Load one last time to reset the state variable in the .sjs file
|
||||
{
|
||||
init: function (xhr) {
|
||||
xhr.open("GET", path + "bug475156.sjs");
|
||||
xhr.setRequestHeader("If-Match", "a1");
|
||||
},
|
||||
|
||||
loading: function (xhr) {
|
||||
},
|
||||
|
||||
done: function (xhr) {
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
|
@ -280,7 +294,6 @@ function drive(test)
|
|||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include "OggDecoder.h"
|
||||
#include "OggReader.h"
|
||||
#include "OggDemuxer.h"
|
||||
|
||||
#include "WebMDecoder.h"
|
||||
|
@ -39,7 +38,6 @@
|
|||
|
||||
#include "WaveDecoder.h"
|
||||
#include "WaveDemuxer.h"
|
||||
#include "WaveReader.h"
|
||||
|
||||
#include "ADTSDecoder.h"
|
||||
#include "ADTSDemuxer.h"
|
||||
|
@ -66,7 +64,7 @@ CodecListContains(char const *const * aCodecs, const String& aCodec)
|
|||
|
||||
static bool
|
||||
IsOggSupportedType(const nsACString& aType,
|
||||
const nsAString& aCodecs = EmptyString())
|
||||
const nsAString& aCodecs = EmptyString())
|
||||
{
|
||||
return OggDecoder::CanHandleMediaType(aType, aCodecs);
|
||||
}
|
||||
|
@ -77,34 +75,6 @@ IsOggTypeAndEnabled(const nsACString& aType)
|
|||
return IsOggSupportedType(aType);
|
||||
}
|
||||
|
||||
// See http://www.rfc-editor.org/rfc/rfc2361.txt for the definitions
|
||||
// of WAVE media types and codec types. However, the audio/vnd.wave
|
||||
// MIME type described there is not used.
|
||||
static const char* const gWaveTypes[5] = {
|
||||
"audio/x-wav",
|
||||
"audio/wav",
|
||||
"audio/wave",
|
||||
"audio/x-pn-wav",
|
||||
nullptr
|
||||
};
|
||||
|
||||
static char const *const gWaveCodecs[4] = {
|
||||
"1", // Microsoft PCM Format
|
||||
"6", // aLaw Encoding
|
||||
"7", // uLaw Encoding
|
||||
nullptr
|
||||
};
|
||||
|
||||
static bool
|
||||
IsWaveType(const nsACString& aType)
|
||||
{
|
||||
if (!MediaDecoder::IsWaveEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CodecListContains(gWaveTypes, aType);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsWebMSupportedType(const nsACString& aType,
|
||||
const nsAString& aCodecs = EmptyString())
|
||||
|
@ -205,8 +175,8 @@ IsAACSupportedType(const nsACString& aType,
|
|||
}
|
||||
|
||||
static bool
|
||||
IsWAVSupportedType(const nsACString& aType,
|
||||
const nsAString& aCodecs = EmptyString())
|
||||
IsWaveSupportedType(const nsACString& aType,
|
||||
const nsAString& aCodecs = EmptyString())
|
||||
{
|
||||
return WaveDecoder::CanHandleMediaType(aType, aCodecs);
|
||||
}
|
||||
|
@ -237,8 +207,14 @@ CanHandleCodecsType(const MediaContentType& aType,
|
|||
return CANPLAY_NO;
|
||||
}
|
||||
}
|
||||
if (IsWaveType(aType.GetMIMEType())) {
|
||||
codecList = gWaveCodecs;
|
||||
if (IsWaveSupportedType(aType.GetMIMEType())) {
|
||||
if (IsWaveSupportedType(aType.GetMIMEType(), aType.GetCodecs())) {
|
||||
return CANPLAY_YES;
|
||||
} else {
|
||||
// We can only reach this position if a particular codec was requested,
|
||||
// ogg is supported and working: the codec must be invalid.
|
||||
return CANPLAY_NO;
|
||||
}
|
||||
}
|
||||
#if !defined(MOZ_OMX_WEBM_DECODER)
|
||||
if (DecoderTraits::IsWebMTypeAndEnabled(aType.GetMIMEType())) {
|
||||
|
@ -324,7 +300,7 @@ CanHandleMediaType(const MediaContentType& aType,
|
|||
if (IsOggTypeAndEnabled(aType.GetMIMEType())) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
if (IsWaveType(aType.GetMIMEType())) {
|
||||
if (IsWaveSupportedType(aType.GetMIMEType())) {
|
||||
return CANPLAY_MAYBE;
|
||||
}
|
||||
if (DecoderTraits::IsMP4TypeAndEnabled(aType.GetMIMEType(), aDiagnostics)) {
|
||||
|
@ -374,7 +350,7 @@ DecoderTraits::CanHandleContentType(const MediaContentType& aContentType,
|
|||
bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType,
|
||||
DecoderDoctorDiagnostics* aDiagnostics)
|
||||
{
|
||||
if (IsWaveType(nsDependentCString(aMIMEType))) {
|
||||
if (IsWaveSupportedType(nsDependentCString(aMIMEType))) {
|
||||
// We should not return true for Wave types, since there are some
|
||||
// Wave codecs actually in use in the wild that we don't support, and
|
||||
// we should allow those to be handled by plugins or helper apps.
|
||||
|
@ -427,7 +403,7 @@ InstantiateDecoder(const nsACString& aType,
|
|||
decoder = new OggDecoder(aOwner);
|
||||
return decoder.forget();
|
||||
}
|
||||
if (IsWaveType(aType)) {
|
||||
if (IsWaveSupportedType(aType)) {
|
||||
decoder = new WaveDecoder(aOwner);
|
||||
return decoder.forget();
|
||||
}
|
||||
|
@ -495,19 +471,14 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
|
|||
if (IsAACSupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new ADTSDemuxer(aDecoder->GetResource()));
|
||||
} else
|
||||
if (IsWAVSupportedType(aType)) {
|
||||
if (IsWaveSupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new WAVDemuxer(aDecoder->GetResource()));
|
||||
} else
|
||||
if (IsFlacSupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new FlacDemuxer(aDecoder->GetResource()));
|
||||
} else
|
||||
if (IsOggSupportedType(aType)) {
|
||||
decoderReader = MediaPrefs::OggFormatReader() ?
|
||||
static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new OggDemuxer(aDecoder->GetResource()))) :
|
||||
new OggReader(aDecoder);
|
||||
} else
|
||||
if (IsWaveType(aType)) {
|
||||
decoderReader = new WaveReader(aDecoder);
|
||||
decoderReader = new MediaFormatReader(aDecoder, new OggDemuxer(aDecoder->GetResource()));
|
||||
} else
|
||||
#ifdef MOZ_ANDROID_OMX
|
||||
if (MediaDecoder::IsAndroidMediaPluginEnabled() &&
|
||||
|
|
|
@ -357,6 +357,7 @@ public:
|
|||
void Enter()
|
||||
{
|
||||
MOZ_ASSERT(!mMaster->mVideoDecodeSuspended);
|
||||
mMaster->UpdateNextFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE);
|
||||
}
|
||||
|
||||
void Exit() override
|
||||
|
@ -568,6 +569,10 @@ public:
|
|||
|
||||
mMaster->UpdatePlaybackPositionPeriodically();
|
||||
|
||||
// Ensure currentTime is up to date prior updating mNextFrameStatus so that
|
||||
// the MediaDecoderOwner fire events at correct currentTime.
|
||||
mMaster->UpdateNextFrameStatus();
|
||||
|
||||
MOZ_ASSERT(!mMaster->IsPlaying() ||
|
||||
mMaster->IsStateMachineScheduled(),
|
||||
"Must have timer scheduled");
|
||||
|
@ -758,6 +763,7 @@ public:
|
|||
EventVisibility aVisibility)
|
||||
{
|
||||
mSeekJob = Move(aSeekJob);
|
||||
mVisibility = aVisibility;
|
||||
|
||||
// Always switch off the blank decoder otherwise we might become visible
|
||||
// in the middle of seeking and won't have a valid video frame to show
|
||||
|
@ -798,8 +804,11 @@ public:
|
|||
mMaster->UpdatePlaybackPositionInternal(
|
||||
mSeekTask->GetSeekTarget().GetTime().ToMicroseconds());
|
||||
|
||||
if (aVisibility == EventVisibility::Observable) {
|
||||
if (mVisibility == EventVisibility::Observable) {
|
||||
mMaster->mOnPlaybackEvent.Notify(MediaEventType::SeekStarted);
|
||||
// We want dormant actions to be transparent to the user.
|
||||
// So we only notify the change when the seek request is from the user.
|
||||
mMaster->UpdateNextFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING);
|
||||
}
|
||||
|
||||
// Reset our state machine and decoding pipeline before seeking.
|
||||
|
@ -906,6 +915,7 @@ private:
|
|||
void SeekCompleted();
|
||||
|
||||
SeekJob mSeekJob;
|
||||
EventVisibility mVisibility = EventVisibility::Observable;
|
||||
MozPromiseRequestHolder<SeekTask::SeekTaskPromise> mSeekTaskRequest;
|
||||
RefPtr<SeekTask> mSeekTask;
|
||||
};
|
||||
|
@ -939,6 +949,8 @@ public:
|
|||
stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)");
|
||||
|
||||
mMaster->ScheduleStateMachineIn(USECS_PER_S);
|
||||
|
||||
mMaster->UpdateNextFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING);
|
||||
}
|
||||
|
||||
void Step() override;
|
||||
|
@ -1323,6 +1335,8 @@ DecodingFirstFrameState::Enter(SeekJob aPendingSeek)
|
|||
|
||||
// Dispatch tasks to decode first frames.
|
||||
mMaster->DispatchDecodeTasksIfNeeded();
|
||||
|
||||
mMaster->UpdateNextFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE);
|
||||
}
|
||||
|
||||
RefPtr<MediaDecoder::SeekPromise>
|
||||
|
@ -1519,6 +1533,10 @@ SeekingState::SeekCompleted()
|
|||
mMaster->mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
|
||||
}
|
||||
|
||||
if (mVisibility == EventVisibility::Observable) {
|
||||
mMaster->UpdateNextFrameStatus();
|
||||
}
|
||||
|
||||
if (nextState == DECODER_STATE_COMPLETED) {
|
||||
SetState<CompletedState>();
|
||||
} else {
|
||||
|
@ -1666,7 +1684,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
mWatchManager(this, mTaskQueue),
|
||||
mDispatchedStateMachine(false),
|
||||
mDelayedScheduler(mTaskQueue),
|
||||
INIT_WATCHABLE(mState, DECODER_STATE_DECODING_METADATA),
|
||||
mCurrentFrameID(0),
|
||||
INIT_WATCHABLE(mObservedDuration, TimeUnit()),
|
||||
mFragmentEndTime(-1),
|
||||
|
@ -1677,8 +1694,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
mLowAudioThresholdUsecs(detail::LOW_AUDIO_USECS),
|
||||
mAmpleAudioThresholdUsecs(detail::AMPLE_AUDIO_USECS),
|
||||
mAudioCaptured(false),
|
||||
INIT_WATCHABLE(mAudioCompleted, false),
|
||||
INIT_WATCHABLE(mVideoCompleted, false),
|
||||
mNotifyMetadataBeforeFirstFrame(false),
|
||||
mMinimizePreroll(false),
|
||||
mSentLoadedMetadataEvent(false),
|
||||
|
@ -1758,9 +1773,6 @@ MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
|
|||
|
||||
// Initialize watchers.
|
||||
mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated);
|
||||
mWatchManager.Watch(mState, &MediaDecoderStateMachine::UpdateNextFrameStatus);
|
||||
mWatchManager.Watch(mAudioCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
|
||||
mWatchManager.Watch(mVideoCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
|
||||
mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
|
||||
mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
|
||||
mWatchManager.Watch(mEstimatedDuration, &MediaDecoderStateMachine::RecomputeDuration);
|
||||
|
@ -1997,7 +2009,6 @@ MediaDecoderStateMachine::Push(MediaData* aSample, MediaData::Type aSampleType)
|
|||
} else {
|
||||
// TODO: Handle MediaRawData, determine which queue should be pushed.
|
||||
}
|
||||
UpdateNextFrameStatus();
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
}
|
||||
|
||||
|
@ -2007,7 +2018,6 @@ MediaDecoderStateMachine::OnAudioPopped(const RefPtr<MediaData>& aSample)
|
|||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
|
||||
UpdateNextFrameStatus();
|
||||
DispatchAudioDecodeTaskIfNeeded();
|
||||
}
|
||||
|
||||
|
@ -2016,7 +2026,6 @@ MediaDecoderStateMachine::OnVideoPopped(const RefPtr<MediaData>& aSample)
|
|||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
|
||||
UpdateNextFrameStatus();
|
||||
DispatchVideoDecodeTaskIfNeeded();
|
||||
}
|
||||
|
||||
|
@ -2928,41 +2937,36 @@ MediaDecoderStateMachine::UpdatePlaybackPositionPeriodically()
|
|||
ScheduleStateMachineIn(delay);
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::UpdateNextFrameStatus()
|
||||
/* static */ const char*
|
||||
MediaDecoderStateMachine::ToStr(NextFrameStatus aStatus)
|
||||
{
|
||||
switch (aStatus) {
|
||||
case MediaDecoderOwner::NEXT_FRAME_AVAILABLE: return "NEXT_FRAME_AVAILABLE";
|
||||
case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE: return "NEXT_FRAME_UNAVAILABLE";
|
||||
case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING: return "NEXT_FRAME_UNAVAILABLE_BUFFERING";
|
||||
case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING: return "NEXT_FRAME_UNAVAILABLE_SEEKING";
|
||||
case MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED: return "NEXT_FRAME_UNINITIALIZED";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::UpdateNextFrameStatus(NextFrameStatus aStatus)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
MediaDecoderOwner::NextFrameStatus status;
|
||||
const char* statusString;
|
||||
|
||||
switch (mState.Ref()) {
|
||||
case DECODER_STATE_BUFFERING:
|
||||
status = MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING;
|
||||
statusString = "NEXT_FRAME_UNAVAILABLE_BUFFERING";
|
||||
break;
|
||||
case DECODER_STATE_SEEKING:
|
||||
status = MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING;
|
||||
statusString = "NEXT_FRAME_UNAVAILABLE_SEEKING";
|
||||
break;
|
||||
default:
|
||||
bool b = HaveNextFrameData();
|
||||
status = b ? MediaDecoderOwner::NEXT_FRAME_AVAILABLE :
|
||||
MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
|
||||
statusString = b ? "NEXT_FRAME_AVAILABLE" : "NEXT_FRAME_UNAVAILABLE";
|
||||
break;
|
||||
if (aStatus != mNextFrameStatus) {
|
||||
DECODER_LOG("Changed mNextFrameStatus to %s", ToStr(aStatus));
|
||||
mNextFrameStatus = aStatus;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != mNextFrameStatus) {
|
||||
DECODER_LOG("Changed mNextFrameStatus to %s", statusString);
|
||||
if(status == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING ||
|
||||
status == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE) {
|
||||
// Ensure currentTime is up to date prior updating mNextFrameStatus so that
|
||||
// the MediaDecoderOwner fire events at correct currentTime.
|
||||
UpdatePlaybackPositionPeriodically();
|
||||
}
|
||||
}
|
||||
|
||||
mNextFrameStatus = status;
|
||||
void
|
||||
MediaDecoderStateMachine::UpdateNextFrameStatus()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
UpdateNextFrameStatus(HaveNextFrameData()
|
||||
? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
|
||||
: MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -3230,7 +3234,7 @@ MediaDecoderStateMachine::DumpDebugInfo()
|
|||
GetMediaTime(), mMediaSink->IsStarted() ? GetClock() : -1, mMediaSink.get(),
|
||||
ToStateStr(), mPlayState.Ref(), mSentFirstFrameLoadedEvent, IsPlaying(),
|
||||
AudioRequestStatus(), VideoRequestStatus(), mDecodedAudioEndTime, mDecodedVideoEndTime,
|
||||
mAudioCompleted.Ref(), mVideoCompleted.Ref());
|
||||
mAudioCompleted, mVideoCompleted);
|
||||
});
|
||||
|
||||
// Since the task is run asynchronously, it is possible other tasks get first
|
||||
|
|
|
@ -270,6 +270,7 @@ private:
|
|||
class ShutdownState;
|
||||
|
||||
static const char* ToStateStr(State aState);
|
||||
static const char* ToStr(NextFrameStatus aStatus);
|
||||
const char* ToStateStr();
|
||||
|
||||
// Functions used by assertions to ensure we're calling things
|
||||
|
@ -401,6 +402,7 @@ protected:
|
|||
// Recomputes mNextFrameStatus, possibly dispatching notifications to interested
|
||||
// parties.
|
||||
void UpdateNextFrameStatus();
|
||||
void UpdateNextFrameStatus(NextFrameStatus aStatus);
|
||||
|
||||
// Return the current time, either the audio clock if available (if the media
|
||||
// has audio, and the playback is possible), or a clock for the video.
|
||||
|
@ -560,9 +562,7 @@ private:
|
|||
// the decoder, state machine, and main threads.
|
||||
MediaQueue<MediaData> mVideoQueue;
|
||||
|
||||
// The decoder monitor must be obtained before modifying this state.
|
||||
// Accessed on state machine, audio, main, and AV thread.
|
||||
Watchable<State> mState;
|
||||
State mState = DECODER_STATE_DECODING_METADATA;
|
||||
|
||||
UniquePtr<StateObject> mStateObj;
|
||||
|
||||
|
@ -679,17 +679,11 @@ private:
|
|||
// it has stopped.
|
||||
bool mAudioCaptured;
|
||||
|
||||
// True if the audio playback thread has finished. It is finished
|
||||
// when either all the audio frames have completed playing, or we've moved
|
||||
// into shutdown state, and the threads are to be
|
||||
// destroyed. Written by the audio playback thread and read and written by
|
||||
// the state machine thread. Synchronised via decoder monitor.
|
||||
// When data is being sent to a MediaStream, this is true when all data has
|
||||
// been written to the MediaStream.
|
||||
Watchable<bool> mAudioCompleted;
|
||||
// True if all audio frames are already rendered.
|
||||
bool mAudioCompleted = false;
|
||||
|
||||
// True if all video frames are already rendered.
|
||||
Watchable<bool> mVideoCompleted;
|
||||
bool mVideoCompleted = false;
|
||||
|
||||
// Flag whether we notify metadata before decoding the first frame or after.
|
||||
//
|
||||
|
|
|
@ -2300,7 +2300,8 @@ if (privileged) {
|
|||
bool fake = c.mFake.WasPassed()? c.mFake.Value() :
|
||||
Preferences::GetBool("media.navigator.streams.fake");
|
||||
|
||||
bool askPermission = !privileged &&
|
||||
bool askPermission =
|
||||
(!privileged || Preferences::GetBool("media.navigator.permission.force")) &&
|
||||
(!fake || Preferences::GetBool("media.navigator.permission.fake"));
|
||||
|
||||
RefPtr<PledgeSourceSet> p = EnumerateDevicesImpl(windowID, videoType,
|
||||
|
|
|
@ -152,7 +152,6 @@ private:
|
|||
|
||||
// Ogg
|
||||
DECL_MEDIA_PREF("media.ogg.enabled", OggEnabled, bool, true);
|
||||
DECL_MEDIA_PREF("media.format-reader.ogg", OggFormatReader, bool, true);
|
||||
// Flac
|
||||
DECL_MEDIA_PREF("media.ogg.flac.enabled", FlacInOgg, bool, false);
|
||||
DECL_MEDIA_PREF("media.flac.enabled", FlacEnabled, bool, true);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "mp4_demuxer/ByteReader.h"
|
||||
#include "nsTArray.h"
|
||||
#include "OggCodecState.h"
|
||||
#include "OpusParser.h"
|
||||
#include "VideoUtils.h"
|
||||
|
||||
using mp4_demuxer::ByteReader;
|
||||
|
@ -43,6 +44,10 @@ FlacFrameParser::FlacFrameParser()
|
|||
{
|
||||
}
|
||||
|
||||
FlacFrameParser::~FlacFrameParser()
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FlacFrameParser::HeaderBlockLength(const uint8_t* aPacket) const
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@ class FlacFrameParser
|
|||
{
|
||||
public:
|
||||
FlacFrameParser();
|
||||
~FlacFrameParser();
|
||||
|
||||
bool IsHeaderBlock(const uint8_t* aPacket, size_t aLength) const;
|
||||
// Return the length of the block header (METADATA_BLOCK_HEADER+
|
||||
|
@ -56,7 +57,6 @@ private:
|
|||
|
||||
// Used to decode the vorbis comment metadata.
|
||||
nsAutoPtr<OpusParser> mParser;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -6,18 +6,18 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "nsDebug.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "OggCodecState.h"
|
||||
#include "OggDecoder.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "OpusParser.h"
|
||||
#include "VideoUtils.h"
|
||||
#include <algorithm>
|
||||
|
||||
#include <opus/opus.h>
|
||||
#include "opus/opus_multistream.h"
|
||||
|
||||
// On Android JellyBean, the hardware.h header redefines version_major and
|
||||
// version_minor, which breaks our build. See:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=912702#c6
|
||||
|
|
|
@ -7,18 +7,7 @@
|
|||
#define OggCodecState_h_
|
||||
|
||||
#include <ogg/ogg.h>
|
||||
#include <theora/theoradec.h>
|
||||
#ifdef MOZ_TREMOR
|
||||
#include <tremor/ivorbiscodec.h>
|
||||
#else
|
||||
#include <vorbis/codec.h>
|
||||
#endif
|
||||
#include <opus/opus.h>
|
||||
#include "opus/opus_multistream.h"
|
||||
// For MOZ_SAMPLE_TYPE_*
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
#include <nsAutoPtr.h>
|
||||
#include <nsAutoRef.h>
|
||||
#include <nsDeque.h>
|
||||
|
@ -27,7 +16,12 @@
|
|||
#include "VideoUtils.h"
|
||||
#include "FlacFrameParser.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <theora/theoradec.h>
|
||||
#ifdef MOZ_TREMOR
|
||||
#include <tremor/ivorbiscodec.h>
|
||||
#else
|
||||
#include <vorbis/codec.h>
|
||||
#endif
|
||||
|
||||
// Uncomment the following to validate that we're predicting the number
|
||||
// of Vorbis samples in each packet correctly.
|
||||
|
@ -36,10 +30,12 @@
|
|||
#include <map>
|
||||
#endif
|
||||
|
||||
#include "OpusParser.h"
|
||||
struct OpusMSDecoder;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class OpusParser;
|
||||
|
||||
// Deallocates a packet, used in OggPacketQueue below.
|
||||
class OggPacketDeallocator : public nsDequeFunctor
|
||||
{
|
||||
|
@ -94,11 +90,11 @@ public:
|
|||
};
|
||||
|
||||
virtual ~OggCodecState();
|
||||
|
||||
|
||||
// Factory for creating nsCodecStates. Use instead of constructor.
|
||||
// aPage should be a beginning-of-stream page.
|
||||
static OggCodecState* Create(ogg_page* aPage);
|
||||
|
||||
|
||||
virtual CodecType GetType() { return TYPE_UNKNOWN; }
|
||||
|
||||
// Reads a header packet. Returns false if an error was encountered
|
||||
|
@ -209,7 +205,7 @@ public:
|
|||
// captured.
|
||||
virtual nsresult PageIn(ogg_page* aPage);
|
||||
|
||||
// Number of packets read.
|
||||
// Number of packets read.
|
||||
uint64_t mPacketCount;
|
||||
|
||||
// Serial number of the bitstream.
|
||||
|
@ -224,7 +220,7 @@ public:
|
|||
|
||||
// Is the bitstream active; whether we're decoding and playing this bitstream.
|
||||
bool mActive;
|
||||
|
||||
|
||||
// True when all headers packets have been read.
|
||||
bool mDoneReadingHeaders;
|
||||
|
||||
|
@ -360,7 +356,7 @@ public:
|
|||
int64_t MaxKeyframeOffset();
|
||||
|
||||
// Returns the end time that a granulepos represents.
|
||||
static int64_t Time(th_info* aInfo, int64_t aGranulePos);
|
||||
static int64_t Time(th_info* aInfo, int64_t aGranulePos);
|
||||
|
||||
th_info mInfo;
|
||||
th_comment mComment;
|
||||
|
@ -566,7 +562,7 @@ private:
|
|||
{
|
||||
public:
|
||||
|
||||
nsKeyFrameIndex(int64_t aStartTime, int64_t aEndTime)
|
||||
nsKeyFrameIndex(int64_t aStartTime, int64_t aEndTime)
|
||||
: mStartTime(aStartTime)
|
||||
, mEndTime(aEndTime)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "MediaDecoderStateMachine.h"
|
||||
#include "MediaFormatReader.h"
|
||||
#include "OggDemuxer.h"
|
||||
#include "OggReader.h"
|
||||
#include "OggDecoder.h"
|
||||
#include "nsContentTypeParser.h"
|
||||
|
||||
|
@ -16,16 +15,11 @@ namespace mozilla {
|
|||
|
||||
MediaDecoderStateMachine* OggDecoder::CreateStateMachine()
|
||||
{
|
||||
bool useFormatDecoder = MediaPrefs::OggFormatReader();
|
||||
RefPtr<OggDemuxer> demuxer =
|
||||
useFormatDecoder ? new OggDemuxer(GetResource()) : nullptr;
|
||||
RefPtr<MediaDecoderReader> reader = useFormatDecoder
|
||||
? static_cast<MediaDecoderReader*>(new MediaFormatReader(this, demuxer, GetVideoFrameContainer()))
|
||||
: new OggReader(this);
|
||||
if (useFormatDecoder) {
|
||||
demuxer->SetChainingEvents(&reader->TimedMetadataProducer(),
|
||||
&reader->MediaNotSeekableProducer());
|
||||
}
|
||||
RefPtr<OggDemuxer> demuxer = new OggDemuxer(GetResource());
|
||||
RefPtr<MediaFormatReader> reader =
|
||||
new MediaFormatReader(this, demuxer, GetVideoFrameContainer());
|
||||
demuxer->SetChainingEvents(&reader->TimedMetadataProducer(),
|
||||
&reader->MediaNotSeekableProducer());
|
||||
return new MediaDecoderStateMachine(this, reader);
|
||||
}
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,306 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
#if !defined(OggReader_h_)
|
||||
#define OggReader_h_
|
||||
|
||||
#include <ogg/ogg.h>
|
||||
#include <theora/theoradec.h>
|
||||
#ifdef MOZ_TREMOR
|
||||
#include <tremor/ivorbiscodec.h>
|
||||
#else
|
||||
#include <vorbis/codec.h>
|
||||
#endif
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "MediaResource.h"
|
||||
#include "OggCodecState.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "OggDecoder.h"
|
||||
#include "OggCodecStore.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class OggReader final : public MediaDecoderReader
|
||||
{
|
||||
public:
|
||||
explicit OggReader(AbstractMediaDecoder* aDecoder);
|
||||
|
||||
protected:
|
||||
~OggReader();
|
||||
|
||||
public:
|
||||
nsresult Init() override;
|
||||
nsresult ResetDecode(TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack,
|
||||
TrackInfo::kVideoTrack)) override;
|
||||
bool DecodeAudioData() override;
|
||||
|
||||
// If the Theora granulepos has not been captured, it may read several packets
|
||||
// until one with a granulepos has been captured, to ensure that all packets
|
||||
// read have valid time info.
|
||||
bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) override;
|
||||
|
||||
nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) override;
|
||||
RefPtr<SeekPromise> Seek(SeekTarget aTarget, int64_t aEndTime) override;
|
||||
media::TimeIntervals GetBuffered() override;
|
||||
|
||||
private:
|
||||
bool HasAudio() {
|
||||
return (mVorbisState != 0 && mVorbisState->mActive) ||
|
||||
(mOpusState != 0 && mOpusState->mActive);
|
||||
}
|
||||
|
||||
bool HasVideo() {
|
||||
return mTheoraState != 0 && mTheoraState->mActive;
|
||||
}
|
||||
|
||||
// TODO: DEPRECATED. This uses synchronous decoding.
|
||||
// Stores the presentation time of the first frame we'd be able to play if
|
||||
// we started playback at the current position. Returns the first video
|
||||
// frame, if we have video.
|
||||
void FindStartTime(int64_t& aOutStartTime);
|
||||
RefPtr<AudioData> SyncDecodeToFirstAudioData();
|
||||
RefPtr<VideoData> SyncDecodeToFirstVideoData();
|
||||
|
||||
// This monitor should be taken when reading or writing to mIsChained.
|
||||
ReentrantMonitor mMonitor;
|
||||
|
||||
// Specialized Reset() method to signal if the seek is
|
||||
// to the start of the stream.
|
||||
nsresult ResetDecode(bool start,
|
||||
TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack,
|
||||
TrackInfo::kVideoTrack));
|
||||
|
||||
nsresult SeekInternal(int64_t aTime, int64_t aEndTime);
|
||||
|
||||
bool HasSkeleton() {
|
||||
return mSkeletonState != 0 && mSkeletonState->mActive;
|
||||
}
|
||||
|
||||
// Seeks to the keyframe preceding the target time using available
|
||||
// keyframe indexes.
|
||||
enum IndexedSeekResult {
|
||||
SEEK_OK, // Success.
|
||||
SEEK_INDEX_FAIL, // Failure due to no index, or invalid index.
|
||||
SEEK_FATAL_ERROR // Error returned by a stream operation.
|
||||
};
|
||||
IndexedSeekResult SeekToKeyframeUsingIndex(int64_t aTarget);
|
||||
|
||||
// Rolls back a seek-using-index attempt, returning a failure error code.
|
||||
IndexedSeekResult RollbackIndexedSeek(int64_t aOffset);
|
||||
|
||||
// Represents a section of contiguous media, with a start and end offset,
|
||||
// and the timestamps of the start and end of that range, that is cached.
|
||||
// Used to denote the extremities of a range in which we can seek quickly
|
||||
// (because it's cached).
|
||||
class SeekRange {
|
||||
public:
|
||||
SeekRange()
|
||||
: mOffsetStart(0),
|
||||
mOffsetEnd(0),
|
||||
mTimeStart(0),
|
||||
mTimeEnd(0)
|
||||
{}
|
||||
|
||||
SeekRange(int64_t aOffsetStart,
|
||||
int64_t aOffsetEnd,
|
||||
int64_t aTimeStart,
|
||||
int64_t aTimeEnd)
|
||||
: mOffsetStart(aOffsetStart),
|
||||
mOffsetEnd(aOffsetEnd),
|
||||
mTimeStart(aTimeStart),
|
||||
mTimeEnd(aTimeEnd)
|
||||
{}
|
||||
|
||||
bool IsNull() const {
|
||||
return mOffsetStart == 0 &&
|
||||
mOffsetEnd == 0 &&
|
||||
mTimeStart == 0 &&
|
||||
mTimeEnd == 0;
|
||||
}
|
||||
|
||||
int64_t mOffsetStart, mOffsetEnd; // in bytes.
|
||||
int64_t mTimeStart, mTimeEnd; // in usecs.
|
||||
};
|
||||
|
||||
// Seeks to aTarget usecs in the buffered range aRange using bisection search,
|
||||
// or to the keyframe prior to aTarget if we have video. aAdjustedTarget is
|
||||
// an adjusted version of the target used to account for Opus pre-roll, if
|
||||
// necessary. aStartTime must be the presentation time at the start of media,
|
||||
// and aEndTime the time at end of media. aRanges must be the time/byte ranges
|
||||
// buffered in the media cache as per GetSeekRanges().
|
||||
nsresult SeekInBufferedRange(int64_t aTarget,
|
||||
int64_t aAdjustedTarget,
|
||||
int64_t aStartTime,
|
||||
int64_t aEndTime,
|
||||
const nsTArray<SeekRange>& aRanges,
|
||||
const SeekRange& aRange);
|
||||
|
||||
// Seeks to before aTarget usecs in media using bisection search. If the media
|
||||
// has video, this will seek to before the keyframe required to render the
|
||||
// media at aTarget. Will use aRanges in order to narrow the bisection
|
||||
// search space. aStartTime must be the presentation time at the start of
|
||||
// media, and aEndTime the time at end of media. aRanges must be the time/byte
|
||||
// ranges buffered in the media cache as per GetSeekRanges().
|
||||
nsresult SeekInUnbuffered(int64_t aTarget,
|
||||
int64_t aStartTime,
|
||||
int64_t aEndTime,
|
||||
const nsTArray<SeekRange>& aRanges);
|
||||
|
||||
// Get the end time of aEndOffset. This is the playback position we'd reach
|
||||
// after playback finished at aEndOffset.
|
||||
int64_t RangeEndTime(int64_t aEndOffset);
|
||||
|
||||
// Get the end time of aEndOffset, without reading before aStartOffset.
|
||||
// This is the playback position we'd reach after playback finished at
|
||||
// aEndOffset. If bool aCachedDataOnly is true, then we'll only read
|
||||
// from data which is cached in the media cached, otherwise we'll do
|
||||
// regular blocking reads from the media stream. If bool aCachedDataOnly
|
||||
// is true, this can safely be called on the main thread, otherwise it
|
||||
// must be called on the state machine thread.
|
||||
int64_t RangeEndTime(int64_t aStartOffset,
|
||||
int64_t aEndOffset,
|
||||
bool aCachedDataOnly);
|
||||
|
||||
// Get the start time of the range beginning at aOffset. This is the start
|
||||
// time of the first frame and or audio sample we'd be able to play if we
|
||||
// started playback at aOffset.
|
||||
int64_t RangeStartTime(int64_t aOffset);
|
||||
|
||||
// Performs a seek bisection to move the media stream's read cursor to the
|
||||
// last ogg page boundary which has end time before aTarget usecs on both the
|
||||
// Theora and Vorbis bitstreams. Limits its search to data inside aRange;
|
||||
// i.e. it will only read inside of the aRange's start and end offsets.
|
||||
// aFuzz is the number of usecs of leniency we'll allow; we'll terminate the
|
||||
// seek when we land in the range (aTime - aFuzz, aTime) usecs.
|
||||
nsresult SeekBisection(int64_t aTarget,
|
||||
const SeekRange& aRange,
|
||||
uint32_t aFuzz);
|
||||
|
||||
// Returns true if the serial number is for a stream we encountered
|
||||
// while reading metadata. Call on the main thread only.
|
||||
bool IsKnownStream(uint32_t aSerial);
|
||||
|
||||
// Fills aRanges with SeekRanges denoting the sections of the media which
|
||||
// have been downloaded and are stored in the media cache. The reader
|
||||
// monitor must must be held with exactly one lock count. The MediaResource
|
||||
// must be pinned while calling this.
|
||||
nsresult GetSeekRanges(nsTArray<SeekRange>& aRanges);
|
||||
|
||||
// Returns the range in which you should perform a seek bisection if
|
||||
// you wish to seek to aTarget usecs, given the known (buffered) byte ranges
|
||||
// in aRanges. If aExact is true, we only return an exact copy of a
|
||||
// range in which aTarget lies, or a null range if aTarget isn't contained
|
||||
// in any of the (buffered) ranges. Otherwise, when aExact is false,
|
||||
// we'll construct the smallest possible range we can, based on the times
|
||||
// and byte offsets known in aRanges. We can then use this to minimize our
|
||||
// bisection's search space when the target isn't in a known buffered range.
|
||||
SeekRange SelectSeekRange(const nsTArray<SeekRange>& aRanges,
|
||||
int64_t aTarget,
|
||||
int64_t aStartTime,
|
||||
int64_t aEndTime,
|
||||
bool aExact);
|
||||
private:
|
||||
|
||||
// Decodes a packet of Vorbis data, and inserts its samples into the
|
||||
// audio queue.
|
||||
nsresult DecodeVorbis(ogg_packet* aPacket);
|
||||
|
||||
// Decodes a packet of Opus data, and inserts its samples into the
|
||||
// audio queue.
|
||||
nsresult DecodeOpus(ogg_packet* aPacket);
|
||||
|
||||
// Decodes a packet of Theora data, and inserts its frame into the
|
||||
// video queue. May return NS_ERROR_OUT_OF_MEMORY. Caller must have obtained
|
||||
// the reader's monitor. aTimeThreshold is the current playback position
|
||||
// in media time in microseconds. Frames with an end time before this will
|
||||
// not be enqueued.
|
||||
nsresult DecodeTheora(ogg_packet* aPacket, int64_t aTimeThreshold);
|
||||
|
||||
// Read a page of data from the Ogg file. Returns true if a page has been
|
||||
// read, false if the page read failed or end of file reached.
|
||||
bool ReadOggPage(ogg_page* aPage);
|
||||
|
||||
// Reads and decodes header packets for aState, until either header decode
|
||||
// fails, or is complete. Initializes the codec state before returning.
|
||||
// Returns true if reading headers and initializtion of the stream
|
||||
// succeeds.
|
||||
bool ReadHeaders(OggCodecState* aState);
|
||||
|
||||
// Reads the next link in the chain.
|
||||
bool ReadOggChain();
|
||||
|
||||
// Set this media as being a chain and notifies the state machine that the
|
||||
// media is no longer seekable.
|
||||
void SetChained();
|
||||
|
||||
// Returns the next Ogg packet for an bitstream/codec state. Returns a
|
||||
// pointer to an ogg_packet on success, or nullptr if the read failed.
|
||||
// The caller is responsible for deleting the packet and its |packet| field.
|
||||
ogg_packet* NextOggPacket(OggCodecState* aCodecState);
|
||||
|
||||
// Fills aTracks with the serial numbers of each active stream, for use by
|
||||
// various SkeletonState functions.
|
||||
void BuildSerialList(nsTArray<uint32_t>& aTracks);
|
||||
|
||||
// Setup target bitstreams for decoding.
|
||||
void SetupTargetTheora(TheoraState* aTheoraState);
|
||||
void SetupTargetVorbis(VorbisState* aVorbisState);
|
||||
void SetupTargetOpus(OpusState* aOpusState);
|
||||
void SetupTargetSkeleton(SkeletonState* aSkeletonState);
|
||||
void SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials);
|
||||
|
||||
OggCodecStore mCodecStore;
|
||||
|
||||
// Decode state of the Theora bitstream we're decoding, if we have video.
|
||||
TheoraState* mTheoraState;
|
||||
|
||||
// Decode state of the Vorbis bitstream we're decoding, if we have audio.
|
||||
VorbisState* mVorbisState;
|
||||
|
||||
// Decode state of the Opus bitstream we're decoding, if we have one.
|
||||
OpusState *mOpusState;
|
||||
|
||||
// Represents the user pref media.opus.enabled at the time our
|
||||
// contructor was called. We can't check it dynamically because
|
||||
// we're not on the main thread;
|
||||
bool mOpusEnabled;
|
||||
|
||||
// Decode state of the Skeleton bitstream.
|
||||
SkeletonState* mSkeletonState;
|
||||
|
||||
// Ogg decoding state.
|
||||
ogg_sync_state mOggState;
|
||||
|
||||
// Vorbis/Opus/Theora data used to compute timestamps. This is written on the
|
||||
// decoder thread and read on the main thread. All reading on the main
|
||||
// thread must be done after metadataloaded. We can't use the existing
|
||||
// data in the codec states due to threading issues. You must check the
|
||||
// associated mTheoraState or mVorbisState pointer is non-null before
|
||||
// using this codec data.
|
||||
uint32_t mVorbisSerial;
|
||||
uint32_t mOpusSerial;
|
||||
uint32_t mTheoraSerial;
|
||||
vorbis_info mVorbisInfo;
|
||||
int mOpusPreSkip;
|
||||
th_info mTheoraInfo;
|
||||
|
||||
// The picture region inside Theora frame to be displayed, if we have
|
||||
// a Theora video track.
|
||||
nsIntRect mPicture;
|
||||
|
||||
// True if we are decoding a chained ogg. Reading or writing to this member
|
||||
// should be done with |mMonitor| acquired.
|
||||
bool mIsChained;
|
||||
|
||||
// Number of audio frames decoded so far.
|
||||
int64_t mDecodedAudioFrames;
|
||||
|
||||
MediaResourceIndex mResource;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -4,18 +4,11 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include <algorithm>
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "OpusParser.h"
|
||||
|
||||
#include "nsDebug.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "VideoUtils.h"
|
||||
#include <algorithm>
|
||||
|
||||
#include "opus/opus.h"
|
||||
extern "C" {
|
||||
|
|
|
@ -6,11 +6,6 @@
|
|||
#if !defined(OpusParser_h_)
|
||||
#define OpusParser_h_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <opus/opus.h>
|
||||
#include "opus/opus_multistream.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsString.h"
|
||||
|
||||
|
@ -46,7 +41,6 @@ public:
|
|||
nsTArray<nsCString> mTags; // Unparsed comment strings from the header.
|
||||
|
||||
nsCString mVendorString; // Encoder vendor string from the header.
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -9,7 +9,6 @@ EXPORTS += [
|
|||
'OggCodecStore.h',
|
||||
'OggDecoder.h',
|
||||
'OggDemuxer.h',
|
||||
'OggReader.h',
|
||||
'OggWriter.h',
|
||||
'OpusParser.h',
|
||||
]
|
||||
|
@ -19,7 +18,6 @@ UNIFIED_SOURCES += [
|
|||
'OggCodecStore.cpp',
|
||||
'OggDecoder.cpp',
|
||||
'OggDemuxer.cpp',
|
||||
'OggReader.cpp',
|
||||
'OggWriter.cpp',
|
||||
'OpusParser.cpp',
|
||||
]
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "OpusDecoder.h"
|
||||
#include "OpusParser.h"
|
||||
#include "TimeUnits.h"
|
||||
#include "VorbisUtils.h"
|
||||
#include "VorbisDecoder.h" // For VorbisLayout
|
||||
|
@ -12,9 +13,13 @@
|
|||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h> // For PRId64
|
||||
|
||||
#include "opus/opus.h"
|
||||
extern "C" {
|
||||
#include "opus/opus_multistream.h"
|
||||
}
|
||||
|
||||
#define OPUS_DEBUG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \
|
||||
("OpusDataDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
|
||||
|
|
|
@ -6,14 +6,17 @@
|
|||
#if !defined(OpusDecoder_h_)
|
||||
#define OpusDecoder_h_
|
||||
|
||||
#include "OpusParser.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
struct OpusMSDecoder;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class OpusParser;
|
||||
|
||||
class OpusDataDecoder : public MediaDataDecoder
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -73,6 +73,8 @@ skip-if = android_version == '18' # android(Bug 1189784, timeouts on 4.3 emulato
|
|||
[test_getUserMedia_playAudioTwice.html]
|
||||
[test_getUserMedia_playVideoAudioTwice.html]
|
||||
[test_getUserMedia_playVideoTwice.html]
|
||||
[test_getUserMedia_scarySources.html]
|
||||
skip-if = toolkit == 'android' # no screenshare or windowshare on android
|
||||
[test_getUserMedia_spinEventLoop.html]
|
||||
[test_getUserMedia_stopAudioStream.html]
|
||||
[test_getUserMedia_stopAudioStreamWithFollowupAudio.html]
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
createHTML({title: "Detect screensharing sources that are firefox", bug: "1311048"});
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
const { Services } = SpecialPowers.Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
let observe = topic => new Promise(r => Services.obs.addObserver(function o(...args) {
|
||||
Services.obs.removeObserver(o, topic);
|
||||
r(args);
|
||||
}, topic, false));
|
||||
|
||||
let getDevices = async constraints => {
|
||||
let [{ windowID, innerWindowID, callID }] = await Promise.race([
|
||||
getUserMedia(constraints),
|
||||
observe("getUserMedia:request")
|
||||
]);
|
||||
let window = Services.wm.getOuterWindowWithId(windowID);
|
||||
let devices = await new Promise((resolve, reject) =>
|
||||
window.navigator.mozGetUserMediaDevices({}, resolve, reject,
|
||||
innerWindowID, callID));
|
||||
return devices.map(d => d.QueryInterface(Ci.nsIMediaDevice));
|
||||
};
|
||||
|
||||
runTest(async () => {
|
||||
try {
|
||||
const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
|
||||
if (IsMacOSX10_6orOlder() || isWinXP) {
|
||||
ok(true, "Screensharing disabled for OSX10.6 and WinXP");
|
||||
return;
|
||||
}
|
||||
|
||||
await pushPrefs(["media.navigator.permission.disabled", true],
|
||||
["media.navigator.permission.fake", true],
|
||||
["media.navigator.permission.force", true]);
|
||||
let devices = await getDevices({video: { mediaSource: "window" }});
|
||||
ok(devices.length, "Found one or more windows.");
|
||||
devices = devices.filter(d => d.scary);
|
||||
ok(devices.length, "Found one or more scary windows (our own counts).");
|
||||
devices.filter(d => d.name.includes("MochiTest"));
|
||||
ok(devices.length,
|
||||
"Our own window is among the scary: " + devices.map(d => `"${d.name}"`));
|
||||
|
||||
devices = await getDevices({video: { mediaSource: "screen" }});
|
||||
let numScreens = devices.length;
|
||||
ok(numScreens, "Found one or more screens.");
|
||||
devices = devices.filter(d => d.scary);
|
||||
is(devices.length, numScreens, "All screens are scary.");
|
||||
} catch(e) {
|
||||
ok(false, e);
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -5,9 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WaveDemuxer.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "WaveReader.h"
|
||||
#include "WaveDecoder.h"
|
||||
#include "MediaFormatReader.h"
|
||||
#include "PDMFactory.h"
|
||||
|
@ -23,39 +21,22 @@ WaveDecoder::Clone(MediaDecoderOwner* aOwner)
|
|||
MediaDecoderStateMachine*
|
||||
WaveDecoder::CreateStateMachine()
|
||||
{
|
||||
if (Preferences::GetBool("media.wave.decoder.enabled", false)) {
|
||||
RefPtr<MediaDecoderReader> reader =
|
||||
new MediaFormatReader(this, new WAVDemuxer(GetResource()));
|
||||
return new MediaDecoderStateMachine(this, reader);
|
||||
} else {
|
||||
return new MediaDecoderStateMachine(this, new WaveReader(this));
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
WaveDecoder::IsEnabled()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!Preferences::GetBool("media.wave.decoder.enabled", false)) {
|
||||
return false;
|
||||
}
|
||||
RefPtr<PDMFactory> platform = new PDMFactory();
|
||||
return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/x-wav"),
|
||||
/* DecoderDoctorDiagnostics* */ nullptr);
|
||||
return new MediaDecoderStateMachine(
|
||||
this, new MediaFormatReader(this, new WAVDemuxer(GetResource())));
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
WaveDecoder::CanHandleMediaType(const nsACString& aType,
|
||||
const nsAString& aCodecs)
|
||||
const nsAString& aCodecs)
|
||||
{
|
||||
if (!IsWaveEnabled()) {
|
||||
return false;
|
||||
}
|
||||
if (aType.EqualsASCII("audio/wave") || aType.EqualsASCII("audio/x-wav") ||
|
||||
aType.EqualsASCII("audio/wav") || aType.EqualsASCII("audio/x-pn-wav")) {
|
||||
return IsEnabled() && (aCodecs.IsEmpty() ||
|
||||
aCodecs.EqualsASCII("1") ||
|
||||
aCodecs.EqualsASCII("6") ||
|
||||
aCodecs.EqualsASCII("7"));
|
||||
return (aCodecs.IsEmpty() || aCodecs.EqualsASCII("1") ||
|
||||
aCodecs.EqualsASCII("6") || aCodecs.EqualsASCII("7"));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -17,9 +17,6 @@ public:
|
|||
MediaDecoder* Clone(MediaDecoderOwner* aOwner) override;
|
||||
MediaDecoderStateMachine* CreateStateMachine() override;
|
||||
|
||||
// Returns true if the WAV backend is pref'ed on, and we're running on a
|
||||
// platform that is likely to have decoders for the format.
|
||||
static bool IsEnabled();
|
||||
static bool CanHandleMediaType(const nsACString& aType,
|
||||
const nsAString& aCodecs);
|
||||
};
|
||||
|
|
|
@ -1,689 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "nsError.h"
|
||||
#include "AbstractMediaDecoder.h"
|
||||
#include "WaveReader.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "nsISeekableStream.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla::media;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Un-comment to enable logging of seek bisections.
|
||||
//#define SEEK_LOGGING
|
||||
|
||||
extern LazyLogModule gMediaDecoderLog;
|
||||
#define LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
|
||||
#ifdef SEEK_LOGGING
|
||||
#define SEEK_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
|
||||
#else
|
||||
#define SEEK_LOG(type, msg)
|
||||
#endif
|
||||
|
||||
struct waveIdToName {
|
||||
uint32_t id;
|
||||
nsCString name;
|
||||
};
|
||||
|
||||
|
||||
// Magic values that identify RIFF chunks we're interested in.
|
||||
static const uint32_t RIFF_CHUNK_MAGIC = 0x52494646;
|
||||
static const uint32_t WAVE_CHUNK_MAGIC = 0x57415645;
|
||||
static const uint32_t FRMT_CHUNK_MAGIC = 0x666d7420;
|
||||
static const uint32_t DATA_CHUNK_MAGIC = 0x64617461;
|
||||
static const uint32_t LIST_CHUNK_MAGIC = 0x4c495354;
|
||||
|
||||
// Size of chunk header. 4 byte chunk header type and 4 byte size field.
|
||||
static const uint16_t CHUNK_HEADER_SIZE = 8;
|
||||
|
||||
// Size of RIFF header. RIFF chunk and 4 byte RIFF type.
|
||||
static const uint16_t RIFF_INITIAL_SIZE = CHUNK_HEADER_SIZE + 4;
|
||||
|
||||
// Size of required part of format chunk. Actual format chunks may be
|
||||
// extended (for non-PCM encodings), but we skip any extended data.
|
||||
static const uint16_t WAVE_FORMAT_CHUNK_SIZE = 16;
|
||||
|
||||
// PCM encoding type from format chunk. Linear PCM is the only encoding
|
||||
// supported by AudioStream.
|
||||
static const uint16_t WAVE_FORMAT_ENCODING_PCM = 1;
|
||||
|
||||
// We reject files with more than this number of channels if we're decoding for
|
||||
// playback.
|
||||
static const uint8_t MAX_CHANNELS = 2;
|
||||
|
||||
namespace {
|
||||
uint32_t
|
||||
ReadUint32BE(const char** aBuffer)
|
||||
{
|
||||
uint32_t result = BigEndian::readUint32(*aBuffer);
|
||||
*aBuffer += sizeof(uint32_t);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ReadUint32LE(const char** aBuffer)
|
||||
{
|
||||
uint32_t result = LittleEndian::readUint32(*aBuffer);
|
||||
*aBuffer += sizeof(uint32_t);
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t
|
||||
ReadInt24LE(const char** aBuffer)
|
||||
{
|
||||
int32_t result = int32_t((uint8_t((*aBuffer)[2]) << 16) |
|
||||
(uint8_t((*aBuffer)[1]) << 8 ) |
|
||||
(uint8_t((*aBuffer)[0])));
|
||||
if (((*aBuffer)[2] & 0x80) == 0x80) {
|
||||
result = (result | 0xff000000);
|
||||
}
|
||||
|
||||
*aBuffer += 3 * sizeof(char);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ReadUint16LE(const char** aBuffer)
|
||||
{
|
||||
uint16_t result = LittleEndian::readUint16(*aBuffer);
|
||||
*aBuffer += sizeof(uint16_t);
|
||||
return result;
|
||||
}
|
||||
|
||||
int16_t
|
||||
ReadInt16LE(const char** aBuffer)
|
||||
{
|
||||
uint16_t result = LittleEndian::readInt16(*aBuffer);
|
||||
*aBuffer += sizeof(int16_t);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ReadUint8(const char** aBuffer)
|
||||
{
|
||||
uint8_t result = uint8_t((*aBuffer)[0]);
|
||||
*aBuffer += sizeof(uint8_t);
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
WaveReader::WaveReader(AbstractMediaDecoder* aDecoder)
|
||||
: MediaDecoderReader(aDecoder)
|
||||
, mResource(aDecoder->GetResource())
|
||||
{
|
||||
MOZ_COUNT_CTOR(WaveReader);
|
||||
}
|
||||
|
||||
WaveReader::~WaveReader()
|
||||
{
|
||||
MOZ_COUNT_DTOR(WaveReader);
|
||||
}
|
||||
|
||||
nsresult WaveReader::ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
bool loaded = LoadRIFFChunk();
|
||||
if (!loaded) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoPtr<dom::HTMLMediaElement::MetadataTags> tags;
|
||||
|
||||
bool loadAllChunks = LoadAllChunks(tags);
|
||||
if (!loadAllChunks) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mInfo.mAudio.mRate = mSampleRate;
|
||||
mInfo.mAudio.mChannels = mChannels;
|
||||
mInfo.mMetadataDuration.emplace(TimeUnit::FromSeconds(BytesToTime(GetDataLength())));
|
||||
|
||||
*aInfo = mInfo;
|
||||
|
||||
*aTags = tags.forget();
|
||||
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template <typename T> T UnsignedByteToAudioSample(uint8_t aValue);
|
||||
template <typename T> T SignedShortToAudioSample(int16_t aValue);
|
||||
template <typename T> T Signed24bIntToAudioSample(int32_t aValue);
|
||||
|
||||
template <> inline float
|
||||
UnsignedByteToAudioSample<float>(uint8_t aValue)
|
||||
{
|
||||
return aValue * (2.0f / UINT8_MAX) - 1.0f;
|
||||
}
|
||||
template <> inline int16_t
|
||||
UnsignedByteToAudioSample<int16_t>(uint8_t aValue)
|
||||
{
|
||||
return int16_t(aValue * UINT16_MAX / UINT8_MAX + INT16_MIN);
|
||||
}
|
||||
|
||||
template <> inline float
|
||||
SignedShortToAudioSample<float>(int16_t aValue)
|
||||
{
|
||||
return AudioSampleToFloat(aValue);
|
||||
}
|
||||
template <> inline int16_t
|
||||
SignedShortToAudioSample<int16_t>(int16_t aValue)
|
||||
{
|
||||
return aValue;
|
||||
}
|
||||
|
||||
template <> inline float
|
||||
Signed24bIntToAudioSample<float>(int32_t aValue)
|
||||
{
|
||||
return aValue / 8388608.0f;
|
||||
}
|
||||
|
||||
template <> inline int16_t
|
||||
Signed24bIntToAudioSample<int16_t>(int32_t aValue)
|
||||
{
|
||||
return aValue / 256;
|
||||
}
|
||||
|
||||
bool WaveReader::DecodeAudioData()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
int64_t pos = GetPosition() - mWavePCMOffset;
|
||||
int64_t len = GetDataLength();
|
||||
int64_t remaining = len - pos;
|
||||
NS_ASSERTION(remaining >= 0, "Current wave position is greater than wave file length");
|
||||
|
||||
static const int64_t BLOCK_SIZE = 6144;
|
||||
int64_t readSize = std::min(BLOCK_SIZE, remaining);
|
||||
int64_t frames = readSize / mFrameSize;
|
||||
|
||||
MOZ_ASSERT(BLOCK_SIZE % 3 == 0);
|
||||
MOZ_ASSERT(BLOCK_SIZE % 2 == 0);
|
||||
|
||||
static_assert(uint64_t(BLOCK_SIZE) < UINT_MAX /
|
||||
sizeof(AudioDataValue) / MAX_CHANNELS,
|
||||
"bufferSize calculation could overflow.");
|
||||
const size_t bufferSize = static_cast<size_t>(frames * mChannels);
|
||||
AlignedAudioBuffer sampleBuffer(bufferSize);
|
||||
if (!sampleBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static_assert(uint64_t(BLOCK_SIZE) < UINT_MAX / sizeof(char),
|
||||
"BLOCK_SIZE too large for enumerator.");
|
||||
auto dataBuffer = MakeUnique<char[]>(static_cast<size_t>(readSize));
|
||||
|
||||
if (!ReadAll(dataBuffer.get(), readSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert data to samples
|
||||
const char* d = dataBuffer.get();
|
||||
AudioDataValue* s = sampleBuffer.get();
|
||||
for (int i = 0; i < frames; ++i) {
|
||||
for (unsigned int j = 0; j < mChannels; ++j) {
|
||||
if (mSampleFormat == FORMAT_U8) {
|
||||
uint8_t v = ReadUint8(&d);
|
||||
*s++ = UnsignedByteToAudioSample<AudioDataValue>(v);
|
||||
} else if (mSampleFormat == FORMAT_S16) {
|
||||
int16_t v = ReadInt16LE(&d);
|
||||
*s++ = SignedShortToAudioSample<AudioDataValue>(v);
|
||||
} else if (mSampleFormat == FORMAT_S24) {
|
||||
int32_t v = ReadInt24LE(&d);
|
||||
*s++ = Signed24bIntToAudioSample<AudioDataValue>(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double posTime = BytesToTime(pos);
|
||||
double readSizeTime = BytesToTime(readSize);
|
||||
NS_ASSERTION(posTime <= INT64_MAX / USECS_PER_S, "posTime overflow");
|
||||
NS_ASSERTION(readSizeTime <= INT64_MAX / USECS_PER_S, "readSizeTime overflow");
|
||||
NS_ASSERTION(frames < INT32_MAX, "frames overflow");
|
||||
|
||||
mAudioQueue.Push(new AudioData(pos,
|
||||
static_cast<int64_t>(posTime * USECS_PER_S),
|
||||
static_cast<int64_t>(readSizeTime * USECS_PER_S),
|
||||
static_cast<int32_t>(frames),
|
||||
Move(sampleBuffer),
|
||||
mChannels,
|
||||
mSampleRate));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WaveReader::DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
int64_t aTimeThreshold)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<MediaDecoderReader::SeekPromise>
|
||||
WaveReader::Seek(SeekTarget aTarget, int64_t aEndTime)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
LOG(LogLevel::Debug, ("%p About to seek to %lld", mDecoder, aTarget.GetTime().ToMicroseconds()));
|
||||
|
||||
if (NS_FAILED(ResetDecode())) {
|
||||
return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
double d = BytesToTime(GetDataLength());
|
||||
NS_ASSERTION(d < INT64_MAX / USECS_PER_S, "Duration overflow");
|
||||
media::TimeUnit duration = media::TimeUnit::FromSeconds(d);
|
||||
double seekTime = std::min(aTarget.GetTime(), duration).ToSeconds();
|
||||
int64_t position = RoundDownToFrame(static_cast<int64_t>(TimeToBytes(seekTime)));
|
||||
NS_ASSERTION(INT64_MAX - mWavePCMOffset > position, "Integer overflow during wave seek");
|
||||
position += mWavePCMOffset;
|
||||
nsresult res = mResource.Seek(nsISeekableStream::NS_SEEK_SET, position);
|
||||
if (NS_FAILED(res)) {
|
||||
return SeekPromise::CreateAndReject(res, __func__);
|
||||
} else {
|
||||
return SeekPromise::CreateAndResolve(aTarget.GetTime(), __func__);
|
||||
}
|
||||
}
|
||||
|
||||
media::TimeIntervals WaveReader::GetBuffered()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
if (!mInfo.HasAudio()) {
|
||||
return media::TimeIntervals();
|
||||
}
|
||||
media::TimeIntervals buffered;
|
||||
AutoPinned<MediaResource> resource(mDecoder->GetResource());
|
||||
int64_t startOffset = resource->GetNextCachedData(mWavePCMOffset);
|
||||
while (startOffset >= 0) {
|
||||
int64_t endOffset = resource->GetCachedDataEnd(startOffset);
|
||||
// Bytes [startOffset..endOffset] are cached.
|
||||
NS_ASSERTION(startOffset >= mWavePCMOffset, "Integer underflow in GetBuffered");
|
||||
NS_ASSERTION(endOffset >= mWavePCMOffset, "Integer underflow in GetBuffered");
|
||||
|
||||
// We need to round the buffered ranges' times to microseconds so that they
|
||||
// have the same precision as the currentTime and duration attribute on
|
||||
// the media element.
|
||||
buffered += media::TimeInterval(
|
||||
media::TimeUnit::FromSeconds(BytesToTime(startOffset - mWavePCMOffset)),
|
||||
media::TimeUnit::FromSeconds(BytesToTime(endOffset - mWavePCMOffset)));
|
||||
startOffset = resource->GetNextCachedData(endOffset);
|
||||
}
|
||||
return buffered;
|
||||
}
|
||||
|
||||
bool
|
||||
WaveReader::ReadAll(char* aBuf, int64_t aSize, int64_t* aBytesRead)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
if (aBytesRead) {
|
||||
*aBytesRead = 0;
|
||||
}
|
||||
uint32_t read = 0;
|
||||
if (NS_FAILED(mResource.Read(aBuf, uint32_t(aSize), &read))) {
|
||||
NS_WARNING("Resource read failed");
|
||||
return false;
|
||||
}
|
||||
if (!read) {
|
||||
return false;
|
||||
}
|
||||
if (aBytesRead) {
|
||||
*aBytesRead = read;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WaveReader::LoadRIFFChunk()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
char riffHeader[RIFF_INITIAL_SIZE];
|
||||
const char* p = riffHeader;
|
||||
|
||||
MOZ_ASSERT(mResource.Tell() == 0,
|
||||
"LoadRIFFChunk called when resource in invalid state");
|
||||
|
||||
if (!ReadAll(riffHeader, sizeof(riffHeader))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static_assert(sizeof(uint32_t) * 3 <= RIFF_INITIAL_SIZE,
|
||||
"Reads would overflow riffHeader buffer.");
|
||||
if (ReadUint32BE(&p) != RIFF_CHUNK_MAGIC) {
|
||||
NS_WARNING("resource data not in RIFF format");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip over RIFF size field.
|
||||
p += sizeof(uint32_t);
|
||||
|
||||
if (ReadUint32BE(&p) != WAVE_CHUNK_MAGIC) {
|
||||
NS_WARNING("Expected WAVE chunk");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WaveReader::LoadFormatChunk(uint32_t aChunkSize)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
uint32_t rate, channels, frameSize, sampleFormat;
|
||||
char waveFormat[WAVE_FORMAT_CHUNK_SIZE];
|
||||
const char* p = waveFormat;
|
||||
|
||||
// RIFF chunks are always word (two byte) aligned.
|
||||
MOZ_ASSERT(mResource.Tell() % 2 == 0,
|
||||
"LoadFormatChunk called with unaligned resource");
|
||||
|
||||
if (!ReadAll(waveFormat, sizeof(waveFormat))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static_assert(sizeof(uint16_t) +
|
||||
sizeof(uint16_t) +
|
||||
sizeof(uint32_t) +
|
||||
4 +
|
||||
sizeof(uint16_t) +
|
||||
sizeof(uint16_t) <= sizeof(waveFormat),
|
||||
"Reads would overflow waveFormat buffer.");
|
||||
if (ReadUint16LE(&p) != WAVE_FORMAT_ENCODING_PCM) {
|
||||
NS_WARNING("WAVE is not uncompressed PCM, compressed encodings are not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
channels = ReadUint16LE(&p);
|
||||
rate = ReadUint32LE(&p);
|
||||
|
||||
// Skip over average bytes per second field.
|
||||
p += 4;
|
||||
|
||||
frameSize = ReadUint16LE(&p);
|
||||
|
||||
sampleFormat = ReadUint16LE(&p);
|
||||
|
||||
// PCM encoded WAVEs are not expected to have an extended "format" chunk,
|
||||
// but I have found WAVEs that have a extended "format" chunk with an
|
||||
// extension size of 0 bytes. Be polite and handle this rather than
|
||||
// considering the file invalid. This code skips any extension of the
|
||||
// "format" chunk.
|
||||
if (aChunkSize > WAVE_FORMAT_CHUNK_SIZE) {
|
||||
uint16_t extra = aChunkSize - WAVE_FORMAT_CHUNK_SIZE;
|
||||
extra += extra % 2;
|
||||
if (NS_FAILED(mResource.Seek(nsISeekableStream::NS_SEEK_CUR, extra))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// RIFF chunks are always word (two byte) aligned.
|
||||
MOZ_ASSERT(mResource.Tell() % 2 == 0,
|
||||
"LoadFormatChunk left resource unaligned");
|
||||
|
||||
// Make sure metadata is fairly sane. The rate check is fairly arbitrary,
|
||||
// but the channels check is intentionally limited to mono or stereo
|
||||
// when the media is intended for direct playback because that's what the
|
||||
// audio backend currently supports.
|
||||
unsigned int actualFrameSize = sampleFormat * channels / 8;
|
||||
if (rate < 100 || rate > 96000 ||
|
||||
(((channels < 1 || channels > MAX_CHANNELS) ||
|
||||
(frameSize != 1 && frameSize != 2 && frameSize != 3 &&
|
||||
frameSize != 4 && frameSize != 6)) &&
|
||||
!mIgnoreAudioOutputFormat) ||
|
||||
(sampleFormat != 8 && sampleFormat != 16 && sampleFormat != 24) ||
|
||||
frameSize != actualFrameSize) {
|
||||
NS_WARNING("Invalid WAVE metadata");
|
||||
return false;
|
||||
}
|
||||
|
||||
mSampleRate = rate;
|
||||
mChannels = channels;
|
||||
mFrameSize = frameSize;
|
||||
if (sampleFormat == 8) {
|
||||
mSampleFormat = FORMAT_U8;
|
||||
} else if (sampleFormat == 24) {
|
||||
mSampleFormat = FORMAT_S24;
|
||||
} else {
|
||||
mSampleFormat = FORMAT_S16;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WaveReader::FindDataOffset(uint32_t aChunkSize)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
// RIFF chunks are always word (two byte) aligned.
|
||||
MOZ_ASSERT(mResource.Tell() % 2 == 0,
|
||||
"FindDataOffset called with unaligned resource");
|
||||
|
||||
int64_t offset = mResource.Tell();
|
||||
if (offset <= 0 || offset > UINT32_MAX) {
|
||||
NS_WARNING("PCM data offset out of range");
|
||||
return false;
|
||||
}
|
||||
|
||||
mWaveLength = aChunkSize;
|
||||
mWavePCMOffset = uint32_t(offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
double
|
||||
WaveReader::BytesToTime(int64_t aBytes) const
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(aBytes >= 0, "Must be >= 0");
|
||||
return float(aBytes) / mSampleRate / mFrameSize;
|
||||
}
|
||||
|
||||
int64_t
|
||||
WaveReader::TimeToBytes(double aTime) const
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(aTime >= 0.0f, "Must be >= 0");
|
||||
return RoundDownToFrame(int64_t(aTime * mSampleRate * mFrameSize));
|
||||
}
|
||||
|
||||
int64_t
|
||||
WaveReader::RoundDownToFrame(int64_t aBytes) const
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(aBytes >= 0, "Must be >= 0");
|
||||
return aBytes - (aBytes % mFrameSize);
|
||||
}
|
||||
|
||||
int64_t
|
||||
WaveReader::GetDataLength()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
int64_t length = mWaveLength;
|
||||
// If the decoder has a valid content length, and it's shorter than the
|
||||
// expected length of the PCM data, calculate the playback duration from
|
||||
// the content length rather than the expected PCM data length.
|
||||
int64_t streamLength = mDecoder->GetResource()->GetLength();
|
||||
if (streamLength >= 0) {
|
||||
int64_t dataLength = std::max<int64_t>(0, streamLength - mWavePCMOffset);
|
||||
length = std::min(dataLength, length);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
int64_t
|
||||
WaveReader::GetPosition()
|
||||
{
|
||||
return mResource.Tell();
|
||||
}
|
||||
|
||||
bool
|
||||
WaveReader::LoadListChunk(uint32_t aChunkSize,
|
||||
nsAutoPtr<dom::HTMLMediaElement::MetadataTags> &aTags)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
// List chunks are always word (two byte) aligned.
|
||||
MOZ_ASSERT(mResource.Tell() % 2 == 0,
|
||||
"LoadListChunk called with unaligned resource");
|
||||
|
||||
static const unsigned int MAX_CHUNK_SIZE = 1 << 16;
|
||||
static_assert(uint64_t(MAX_CHUNK_SIZE) < UINT_MAX / sizeof(char),
|
||||
"MAX_CHUNK_SIZE too large for enumerator.");
|
||||
|
||||
if (aChunkSize > MAX_CHUNK_SIZE || aChunkSize < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto chunk = MakeUnique<char[]>(aChunkSize);
|
||||
if (!ReadAll(chunk.get(), aChunkSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const uint32_t INFO_LIST_MAGIC = 0x494e464f;
|
||||
const char* p = chunk.get();
|
||||
if (ReadUint32BE(&p) != INFO_LIST_MAGIC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const waveIdToName ID_TO_NAME[] = {
|
||||
{ 0x49415254, NS_LITERAL_CSTRING("artist") }, // IART
|
||||
{ 0x49434d54, NS_LITERAL_CSTRING("comments") }, // ICMT
|
||||
{ 0x49474e52, NS_LITERAL_CSTRING("genre") }, // IGNR
|
||||
{ 0x494e414d, NS_LITERAL_CSTRING("name") }, // INAM
|
||||
};
|
||||
|
||||
const char* const end = chunk.get() + aChunkSize;
|
||||
|
||||
aTags = new dom::HTMLMediaElement::MetadataTags;
|
||||
|
||||
while (p + 8 < end) {
|
||||
uint32_t id = ReadUint32BE(&p);
|
||||
// Uppercase tag id, inspired by GStreamer's Wave parser.
|
||||
id &= 0xDFDFDFDF;
|
||||
|
||||
uint32_t length = ReadUint32LE(&p);
|
||||
|
||||
// Subchunk shall not exceed parent chunk.
|
||||
if (uint32_t(end - p) < length) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Wrap the string, adjusting length to account for optional
|
||||
// null termination in the chunk.
|
||||
nsCString val(p, length);
|
||||
if (length > 0 && val[length - 1] == '\0') {
|
||||
val.SetLength(length - 1);
|
||||
}
|
||||
|
||||
// Chunks in List::INFO are always word (two byte) aligned. So round up if
|
||||
// necessary.
|
||||
length += length % 2;
|
||||
p += length;
|
||||
|
||||
if (!IsUTF8(val)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mozilla::ArrayLength(ID_TO_NAME); ++i) {
|
||||
if (id == ID_TO_NAME[i].id) {
|
||||
aTags->Put(ID_TO_NAME[i].name, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WaveReader::LoadAllChunks(nsAutoPtr<dom::HTMLMediaElement::MetadataTags> &aTags)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
// Chunks are always word (two byte) aligned.
|
||||
MOZ_ASSERT(mResource.Tell() % 2 == 0,
|
||||
"LoadAllChunks called with unaligned resource");
|
||||
|
||||
bool loadFormatChunk = false;
|
||||
bool findDataOffset = false;
|
||||
|
||||
for (;;) {
|
||||
static const unsigned int CHUNK_HEADER_SIZE = 8;
|
||||
char chunkHeader[CHUNK_HEADER_SIZE];
|
||||
const char* p = chunkHeader;
|
||||
|
||||
if (!ReadAll(chunkHeader, sizeof(chunkHeader))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static_assert(sizeof(uint32_t) * 2 <= CHUNK_HEADER_SIZE,
|
||||
"Reads would overflow chunkHeader buffer.");
|
||||
|
||||
uint32_t magic = ReadUint32BE(&p);
|
||||
uint32_t chunkSize = ReadUint32LE(&p);
|
||||
int64_t chunkStart = GetPosition();
|
||||
|
||||
switch (magic) {
|
||||
case FRMT_CHUNK_MAGIC:
|
||||
loadFormatChunk = LoadFormatChunk(chunkSize);
|
||||
if (!loadFormatChunk) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case LIST_CHUNK_MAGIC:
|
||||
if (!aTags) {
|
||||
LoadListChunk(chunkSize, aTags);
|
||||
}
|
||||
break;
|
||||
|
||||
case DATA_CHUNK_MAGIC:
|
||||
findDataOffset = FindDataOffset(chunkSize);
|
||||
return loadFormatChunk && findDataOffset;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// RIFF chunks are two-byte aligned, so round up if necessary.
|
||||
chunkSize += chunkSize % 2;
|
||||
|
||||
// Move forward to next chunk
|
||||
CheckedInt64 forward = CheckedInt64(chunkStart) + chunkSize - GetPosition();
|
||||
|
||||
if (!forward.isValid() || forward.value() < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const int64_t MAX_CHUNK_SIZE = 1 << 16;
|
||||
static_assert(uint64_t(MAX_CHUNK_SIZE) < UINT_MAX / sizeof(char),
|
||||
"MAX_CHUNK_SIZE too large for enumerator.");
|
||||
auto chunk = MakeUnique<char[]>(MAX_CHUNK_SIZE);
|
||||
while (forward.value() > 0) {
|
||||
int64_t size = std::min(forward.value(), MAX_CHUNK_SIZE);
|
||||
if (!ReadAll(chunk.get(), size)) {
|
||||
return false;
|
||||
}
|
||||
forward -= size;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -1,95 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
#if !defined(WaveReader_h_)
|
||||
#define WaveReader_h_
|
||||
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "MediaResource.h"
|
||||
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WaveReader : public MediaDecoderReader
|
||||
{
|
||||
public:
|
||||
explicit WaveReader(AbstractMediaDecoder* aDecoder);
|
||||
|
||||
protected:
|
||||
~WaveReader();
|
||||
|
||||
public:
|
||||
bool DecodeAudioData() override;
|
||||
bool DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
int64_t aTimeThreshold) override;
|
||||
|
||||
nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) override;
|
||||
RefPtr<SeekPromise> Seek(SeekTarget aTarget, int64_t aEndTime) override;
|
||||
|
||||
media::TimeIntervals GetBuffered() override;
|
||||
|
||||
private:
|
||||
bool ReadAll(char* aBuf, int64_t aSize, int64_t* aBytesRead = nullptr);
|
||||
bool LoadRIFFChunk();
|
||||
bool LoadFormatChunk(uint32_t aChunkSize);
|
||||
bool FindDataOffset(uint32_t aChunkSize);
|
||||
bool LoadListChunk(uint32_t aChunkSize, nsAutoPtr<dom::HTMLMediaElement::MetadataTags> &aTags);
|
||||
bool LoadAllChunks(nsAutoPtr<dom::HTMLMediaElement::MetadataTags> &aTags);
|
||||
|
||||
// Returns the number of seconds that aBytes represents based on the
|
||||
// current audio parameters. e.g. 176400 bytes is 1 second at 16-bit
|
||||
// stereo 44.1kHz. The time is rounded to the nearest microsecond.
|
||||
double BytesToTime(int64_t aBytes) const;
|
||||
|
||||
// Returns the number of bytes that aTime represents based on the current
|
||||
// audio parameters. e.g. 1 second is 176400 bytes at 16-bit stereo
|
||||
// 44.1kHz.
|
||||
int64_t TimeToBytes(double aTime) const;
|
||||
|
||||
// Rounds aBytes down to the nearest complete audio frame. Assumes
|
||||
// beginning of byte range is already frame aligned by caller.
|
||||
int64_t RoundDownToFrame(int64_t aBytes) const;
|
||||
int64_t GetDataLength();
|
||||
int64_t GetPosition();
|
||||
|
||||
/*
|
||||
Metadata extracted from the WAVE header. Used to initialize the audio
|
||||
stream, and for byte<->time domain conversions.
|
||||
*/
|
||||
|
||||
// Number of samples per second. Limited to range [100, 96000] in LoadFormatChunk.
|
||||
uint32_t mSampleRate;
|
||||
|
||||
// Number of channels. Limited to range [1, 2] in LoadFormatChunk.
|
||||
uint32_t mChannels;
|
||||
|
||||
// Size of a single audio frame, which includes a sample for each channel
|
||||
// (interleaved).
|
||||
uint32_t mFrameSize;
|
||||
|
||||
// The sample format of the PCM data. AudioStream::SampleFormat doesn't
|
||||
// support U8.
|
||||
enum {
|
||||
FORMAT_U8,
|
||||
FORMAT_S16,
|
||||
FORMAT_S24
|
||||
} mSampleFormat;
|
||||
|
||||
// Size of PCM data stored in the WAVE as reported by the data chunk in
|
||||
// the media.
|
||||
int64_t mWaveLength;
|
||||
|
||||
// Start offset of the PCM data in the media stream. Extends mWaveLength
|
||||
// bytes.
|
||||
int64_t mWavePCMOffset;
|
||||
|
||||
MediaResourceIndex mResource;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -7,13 +7,11 @@
|
|||
EXPORTS += [
|
||||
'WaveDecoder.h',
|
||||
'WaveDemuxer.h',
|
||||
'WaveReader.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'WaveDecoder.cpp',
|
||||
'WaveDemuxer.cpp',
|
||||
'WaveReader.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
|
|
@ -255,8 +255,8 @@ class SpeechEvent : public Runnable
|
|||
public:
|
||||
SpeechEvent(SpeechRecognition* aRecognition, SpeechRecognition::EventType aType)
|
||||
: mAudioSegment(0)
|
||||
, mRecognitionResultList(0)
|
||||
, mError(0)
|
||||
, mRecognitionResultList(nullptr)
|
||||
, mError(nullptr)
|
||||
, mRecognition(aRecognition)
|
||||
, mType(aType)
|
||||
, mTrackRate(0)
|
||||
|
|
|
@ -132,7 +132,8 @@ Presentation::HasReceiverSupport() const
|
|||
}
|
||||
|
||||
if (!Preferences::GetBool("dom.presentation.testing.simulate-receiver") &&
|
||||
!docShell->GetIsInMozBrowserOrApp()) {
|
||||
!docShell->GetIsInMozBrowserOrApp() &&
|
||||
!docShell->GetIsTopLevelContentDocShell()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1602,8 +1602,9 @@ PresentationPresentingInfo::ResolvedCallback(JSContext* aCx,
|
|||
}
|
||||
|
||||
// Start to listen to document state change event |STATE_TRANSFERRING|.
|
||||
HTMLIFrameElement* frame = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(HTMLIFrameElement, obj, frame);
|
||||
// Use Element to support both HTMLIFrameElement and nsXULElement.
|
||||
Element* frame = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(Element, obj, frame);
|
||||
if (NS_WARN_IF(!frame)) {
|
||||
ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return;
|
||||
|
|
|
@ -0,0 +1,461 @@
|
|||
/* -*- 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/. */
|
||||
/* jshint esnext:true, globalstrict:true, moz:true, undef:true, unused:true */
|
||||
/* globals Components, dump */
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
// globals XPCOMUtils
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
// globals Services
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
// globals Messaging
|
||||
Cu.import("resource://gre/modules/Messaging.jsm");
|
||||
|
||||
function log(str) {
|
||||
// dump("-*- AndroidCastDeviceProvider -*-: " + str + "\n");
|
||||
}
|
||||
|
||||
// Helper function: transfer nsIPresentationChannelDescription to json
|
||||
function descriptionToString(aDescription) {
|
||||
let json = {};
|
||||
json.type = aDescription.type;
|
||||
switch(aDescription.type) {
|
||||
case Ci.nsIPresentationChannelDescription.TYPE_TCP:
|
||||
let addresses = aDescription.tcpAddress.QueryInterface(Ci.nsIArray);
|
||||
json.tcpAddress = [];
|
||||
for (let idx = 0; idx < addresses.length; idx++) {
|
||||
let address = addresses.queryElementAt(idx, Ci.nsISupportsCString);
|
||||
json.tcpAddress.push(address.data);
|
||||
}
|
||||
json.tcpPort = aDescription.tcpPort;
|
||||
break;
|
||||
case Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL:
|
||||
json.dataChannelSDP = aDescription.dataChannelSDP;
|
||||
break;
|
||||
}
|
||||
return JSON.stringify(json);
|
||||
}
|
||||
|
||||
const TOPIC_ANDROID_CAST_DEVICE_SYNCDEVICE = "AndroidCastDevice:SyncDevice";
|
||||
const TOPIC_ANDROID_CAST_DEVICE_ADDED = "AndroidCastDevice:Added";
|
||||
const TOPIC_ANDROID_CAST_DEVICE_REMOVED = "AndroidCastDevice:Removed";
|
||||
const TOPIC_ANDROID_CAST_DEVICE_START = "AndroidCastDevice:Start";
|
||||
const TOPIC_ANDROID_CAST_DEVICE_STOP = "AndroidCastDevice:Stop";
|
||||
const TOPIC_PRESENTATION_VIEW_READY = "presentation-view-ready";
|
||||
|
||||
function LocalControlChannel(aProvider, aDeviceId, aRole) {
|
||||
log("LocalControlChannel - create new LocalControlChannel for : "
|
||||
+ aRole);
|
||||
this._provider = aProvider;
|
||||
this._deviceId = aDeviceId;
|
||||
this._role = aRole;
|
||||
}
|
||||
|
||||
LocalControlChannel.prototype = {
|
||||
_listener: null,
|
||||
_provider: null,
|
||||
_deviceId: null,
|
||||
_role: null,
|
||||
_isOnTerminating: false,
|
||||
_isOnDisconnecting: false,
|
||||
_pendingConnected: false,
|
||||
_pendingDisconnect: null,
|
||||
_pendingOffer: null,
|
||||
_pendingCandidate: null,
|
||||
/* For the controller, it would be the control channel of the receiver.
|
||||
* For the receiver, it would be the control channel of the controller. */
|
||||
_correspondingControlChannel: null,
|
||||
|
||||
set correspondingControlChannel(aCorrespondingControlChannel) {
|
||||
this._correspondingControlChannel = aCorrespondingControlChannel;
|
||||
},
|
||||
|
||||
get correspondingControlChannel() {
|
||||
return this._correspondingControlChannel;
|
||||
},
|
||||
|
||||
notifyConnected: function LCC_notifyConnected() {
|
||||
this._pendingDisconnect = null;
|
||||
|
||||
if (!this._listener) {
|
||||
this._pendingConnected = true;
|
||||
} else {
|
||||
this._listener.notifyConnected();
|
||||
}
|
||||
},
|
||||
|
||||
onOffer: function LCC_onOffer(aOffer) {
|
||||
if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) {
|
||||
log("LocalControlChannel - onOffer of controller should not be called.");
|
||||
return;
|
||||
}
|
||||
if (!this._listener) {
|
||||
this._pendingOffer = aOffer;
|
||||
} else {
|
||||
this._listener.onOffer(aOffer);
|
||||
}
|
||||
},
|
||||
|
||||
onAnswer: function LCC_onAnswer(aAnswer) {
|
||||
if (this._role == Ci.nsIPresentationService.ROLE_RECEIVER) {
|
||||
log("LocalControlChannel - onAnswer of receiver should not be called.");
|
||||
return;
|
||||
}
|
||||
this._listener.onAnswer(aAnswer);
|
||||
},
|
||||
|
||||
notifyIceCandidate: function LCC_notifyIceCandidate(aCandidate) {
|
||||
if (!this._listener) {
|
||||
this._pendingCandidate = aCandidate;
|
||||
} else {
|
||||
this._listener.onIceCandidate(aCandidate);
|
||||
}
|
||||
},
|
||||
|
||||
// nsIPresentationControlChannel
|
||||
get listener() {
|
||||
return this._listener;
|
||||
},
|
||||
|
||||
set listener(aListener) {
|
||||
this._listener = aListener;
|
||||
|
||||
if (!this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._pendingConnected) {
|
||||
this.notifyConnected();
|
||||
this._pendingConnected = false;
|
||||
}
|
||||
|
||||
if (this._pendingOffer) {
|
||||
this.onOffer(this._pendingOffer);
|
||||
this._pendingOffer = null;
|
||||
}
|
||||
|
||||
if (this._pendingCandidate) {
|
||||
this.notifyIceCandidate(this._pendingCandidate);
|
||||
this._pendingCandidate = null;
|
||||
}
|
||||
|
||||
if (this._pendingDisconnect != null) {
|
||||
this.disconnect(this._pendingDisconnect);
|
||||
this._pendingDisconnect = null;
|
||||
}
|
||||
},
|
||||
|
||||
sendOffer: function LCC_sendOffer(aOffer) {
|
||||
if (this._role == Ci.nsIPresentationService.ROLE_RECEIVER) {
|
||||
log("LocalControlChannel - sendOffer of receiver should not be called.");
|
||||
return;
|
||||
}
|
||||
log("LocalControlChannel - sendOffer aOffer=" + descriptionToString(aOffer));
|
||||
this._correspondingControlChannel.onOffer(aOffer);
|
||||
},
|
||||
|
||||
sendAnswer: function LCC_sendAnswer(aAnswer) {
|
||||
if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) {
|
||||
log("LocalControlChannel - sendAnswer of controller should not be called.");
|
||||
return;
|
||||
}
|
||||
log("LocalControlChannel - sendAnswer aAnswer=" + descriptionToString(aAnswer));
|
||||
this._correspondingControlChannel.onAnswer(aAnswer);
|
||||
},
|
||||
|
||||
sendIceCandidate: function LCC_sendIceCandidate(aCandidate) {
|
||||
log("LocalControlChannel - sendAnswer aCandidate=" + aCandidate);
|
||||
this._correspondingControlChannel.notifyIceCandidate(aCandidate);
|
||||
},
|
||||
|
||||
launch: function LCC_launch(aPresentationId, aUrl) {
|
||||
log("LocalControlChannel - launch aPresentationId="
|
||||
+ aPresentationId + " aUrl=" + aUrl);
|
||||
// Create control channel for receiver directly.
|
||||
let controlChannel = new LocalControlChannel(this._provider,
|
||||
this._deviceId,
|
||||
Ci.nsIPresentationService.ROLE_RECEIVER);
|
||||
|
||||
// Set up the corresponding control channels for both controller and receiver.
|
||||
this._correspondingControlChannel = controlChannel;
|
||||
controlChannel._correspondingControlChannel = this;
|
||||
|
||||
this._provider.onSessionRequest(this._deviceId,
|
||||
aUrl,
|
||||
aPresentationId,
|
||||
controlChannel);
|
||||
controlChannel.notifyConnected();
|
||||
},
|
||||
|
||||
terminate: function LCC_terminate(aPresentationId) {
|
||||
log("LocalControlChannel - terminate aPresentationId="
|
||||
+ aPresentationId);
|
||||
|
||||
if (this._isOnTerminating) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create control channel for corresponding role directly.
|
||||
let correspondingRole = this._role == Ci.nsIPresentationService.ROLE_CONTROLLER
|
||||
? Ci.nsIPresentationService.ROLE_RECEIVER
|
||||
: Ci.nsIPresentationService.ROLE_CONTROLLER;
|
||||
let controlChannel = new LocalControlChannel(this._provider,
|
||||
this._deviceId,
|
||||
correspondingRole);
|
||||
// Prevent the termination recursion.
|
||||
controlChannel._isOnTerminating = true;
|
||||
|
||||
// Set up the corresponding control channels for both controller and receiver.
|
||||
this._correspondingControlChannel = controlChannel;
|
||||
controlChannel._correspondingControlChannel = this;
|
||||
|
||||
this._provider.onTerminateRequest(this._deviceId,
|
||||
aPresentationId,
|
||||
controlChannel,
|
||||
this._role == Ci.nsIPresentationService.ROLE_RECEIVER);
|
||||
controlChannel.notifyConnected();
|
||||
},
|
||||
|
||||
disconnect: function LCC_disconnect(aReason) {
|
||||
log("LocalControlChannel - disconnect aReason=" + aReason);
|
||||
|
||||
if (this._isOnDisconnecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._pendingOffer = null;
|
||||
this._pendingCandidate = null;
|
||||
this._pendingConnected = false;
|
||||
|
||||
// this._pendingDisconnect is a nsresult.
|
||||
// If it is null, it means no pending disconnect.
|
||||
// If it is NS_OK, it means this control channel is disconnected normally.
|
||||
// If it is other nsresult value, it means this control channel is
|
||||
// disconnected abnormally.
|
||||
|
||||
// Remote endpoint closes the control channel with abnormal reason.
|
||||
if (aReason == Cr.NS_OK &&
|
||||
this._pendingDisconnect != null &&
|
||||
this._pendingDisconnect != Cr.NS_OK) {
|
||||
aReason = this._pendingDisconnect;
|
||||
}
|
||||
|
||||
if (!this._listener) {
|
||||
this._pendingDisconnect = aReason;
|
||||
return;
|
||||
}
|
||||
|
||||
this._isOnDisconnecting = true;
|
||||
this._correspondingControlChannel.disconnect(aReason);
|
||||
this._listener.notifyDisconnected(aReason);
|
||||
},
|
||||
|
||||
reconnect: function LCC_reconnect(aPresentationId, aUrl) {
|
||||
log("1-UA on Android doesn't support reconnect.");
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
},
|
||||
|
||||
classID: Components.ID("{c9be9450-e5c7-4294-a287-376971b017fd}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
|
||||
};
|
||||
|
||||
function ChromecastRemoteDisplayDevice(aProvider, aId, aName, aRole) {
|
||||
this._provider = aProvider;
|
||||
this._id = aId;
|
||||
this._name = aName;
|
||||
this._role = aRole;
|
||||
}
|
||||
|
||||
ChromecastRemoteDisplayDevice.prototype = {
|
||||
_id: null,
|
||||
_name: null,
|
||||
_role: null,
|
||||
_provider: null,
|
||||
_ctrlChannel: null,
|
||||
|
||||
update: function CRDD_update(aName) {
|
||||
this._name = aName || this._name;
|
||||
},
|
||||
|
||||
// nsIPresentationDevice
|
||||
get id() { return this._id; },
|
||||
|
||||
get name() { return this._name; },
|
||||
|
||||
get type() { return "chromecast"; },
|
||||
|
||||
establishControlChannel: function CRDD_establishControlChannel() {
|
||||
this._ctrlChannel = new LocalControlChannel(this._provider,
|
||||
this._id,
|
||||
this._role);
|
||||
|
||||
if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) {
|
||||
// Only connect to Chromecast for controller.
|
||||
// Monitor the receiver being ready.
|
||||
Services.obs.addObserver(this, TOPIC_PRESENTATION_VIEW_READY, true);
|
||||
|
||||
// Launch Chromecast service in Android.
|
||||
Messaging.sendRequestForResult({
|
||||
type: TOPIC_ANDROID_CAST_DEVICE_START,
|
||||
id: this.id
|
||||
}).then(result => {
|
||||
log("Chromecast is connected.");
|
||||
}).catch(error => {
|
||||
log("Can not connect to Chromecast.");
|
||||
// If Chromecast can not be launched, remove the observer.
|
||||
Services.obs.removeObserver(this, TOPIC_PRESENTATION_VIEW_READY);
|
||||
this._ctrlChannel.disconnect(Cr.NS_ERROR_FAILURE);
|
||||
});
|
||||
} else {
|
||||
// If establishControlChannel called from the receiver, we don't need to
|
||||
// wait the 'presentation-view-ready' event.
|
||||
this._ctrlChannel.notifyConnected();
|
||||
}
|
||||
|
||||
return this._ctrlChannel;
|
||||
},
|
||||
|
||||
disconnect: function CRDD_disconnect() {
|
||||
// Disconnect from Chromecast.
|
||||
Messaging.sendRequestForResult({
|
||||
type: TOPIC_ANDROID_CAST_DEVICE_STOP,
|
||||
id: this.id
|
||||
});
|
||||
},
|
||||
|
||||
isRequestedUrlSupported: function CRDD_isRequestedUrlSupported(aUrl) {
|
||||
let url = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService)
|
||||
.newURI(aUrl, null, null);
|
||||
return url.scheme == "http" || url.scheme == "https";
|
||||
},
|
||||
|
||||
// nsIPresentationLocalDevice
|
||||
get windowId() { return this._id; },
|
||||
|
||||
// nsIObserver
|
||||
observe: function CRDD_observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == TOPIC_PRESENTATION_VIEW_READY) {
|
||||
log("ChromecastRemoteDisplayDevice - observe: aTopic="
|
||||
+ aTopic + " data=" + aData);
|
||||
if (this.windowId === aData) {
|
||||
Services.obs.removeObserver(this, TOPIC_PRESENTATION_VIEW_READY);
|
||||
this._ctrlChannel.notifyConnected();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice,
|
||||
Ci.nsIPresentationLocalDevice,
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsIObserver]),
|
||||
};
|
||||
|
||||
function AndroidCastDeviceProvider() {
|
||||
}
|
||||
|
||||
AndroidCastDeviceProvider.prototype = {
|
||||
_listener: null,
|
||||
_deviceList: new Map(),
|
||||
|
||||
onSessionRequest: function APDP_onSessionRequest(aDeviceId,
|
||||
aUrl,
|
||||
aPresentationId,
|
||||
aControlChannel) {
|
||||
log("AndroidCastDeviceProvider - onSessionRequest"
|
||||
+ " aDeviceId=" + aDeviceId);
|
||||
let device = this._deviceList.get(aDeviceId);
|
||||
let receiverDevice = new ChromecastRemoteDisplayDevice(this,
|
||||
device.id,
|
||||
device.name,
|
||||
Ci.nsIPresentationService.ROLE_RECEIVER);
|
||||
this._listener.onSessionRequest(receiverDevice,
|
||||
aUrl,
|
||||
aPresentationId,
|
||||
aControlChannel);
|
||||
},
|
||||
|
||||
onTerminateRequest: function APDP_onTerminateRequest(aDeviceId,
|
||||
aPresentationId,
|
||||
aControlChannel,
|
||||
aIsFromReceiver) {
|
||||
log("AndroidCastDeviceProvider - onTerminateRequest"
|
||||
+ " aDeviceId=" + aDeviceId
|
||||
+ " aPresentationId=" + aPresentationId
|
||||
+ " aIsFromReceiver=" + aIsFromReceiver);
|
||||
let device = this._deviceList.get(aDeviceId);
|
||||
this._listener.onTerminateRequest(device,
|
||||
aPresentationId,
|
||||
aControlChannel,
|
||||
aIsFromReceiver);
|
||||
},
|
||||
|
||||
// nsIPresentationDeviceProvider
|
||||
set listener(aListener) {
|
||||
this._listener = aListener;
|
||||
|
||||
// When unload this provider.
|
||||
if (!this._listener) {
|
||||
// remove observer
|
||||
Services.obs.removeObserver(this, TOPIC_ANDROID_CAST_DEVICE_ADDED);
|
||||
Services.obs.removeObserver(this, TOPIC_ANDROID_CAST_DEVICE_REMOVED);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sync all device already found by Android.
|
||||
Services.obs.notifyObservers(null, TOPIC_ANDROID_CAST_DEVICE_SYNCDEVICE, "");
|
||||
// Observer registration
|
||||
Services.obs.addObserver(this, TOPIC_ANDROID_CAST_DEVICE_ADDED, false);
|
||||
Services.obs.addObserver(this, TOPIC_ANDROID_CAST_DEVICE_REMOVED, false);
|
||||
},
|
||||
|
||||
get listener() {
|
||||
return this._listener;
|
||||
},
|
||||
|
||||
forceDiscovery: function APDP_forceDiscovery() {
|
||||
// There is no API to do force discovery in Android SDK.
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
observe: function APDP_observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case TOPIC_ANDROID_CAST_DEVICE_ADDED: {
|
||||
let deviceInfo = JSON.parse(aData);
|
||||
let deviceId = deviceInfo.uuid;
|
||||
|
||||
if (!this._deviceList.has(deviceId)) {
|
||||
let device = new ChromecastRemoteDisplayDevice(this,
|
||||
deviceInfo.uuid,
|
||||
deviceInfo.friendlyName,
|
||||
Ci.nsIPresentationService.ROLE_CONTROLLER);
|
||||
this._deviceList.set(device.id, device);
|
||||
this._listener.addDevice(device);
|
||||
} else {
|
||||
let device = this._deviceList.get(deviceId);
|
||||
device.update(deviceInfo.friendlyName);
|
||||
this._listener.updateDevice(device);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TOPIC_ANDROID_CAST_DEVICE_REMOVED: {
|
||||
let deviceId = aData;
|
||||
let device = this._deviceList.get(deviceId);
|
||||
this._listener.removeDevice(device);
|
||||
this._deviceList.delete(deviceId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
classID: Components.ID("{7394f24c-dbc3-48c8-8a47-cd10169b7c6b}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsIPresentationDeviceProvider]),
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AndroidCastDeviceProvider]);
|
|
@ -0,0 +1,4 @@
|
|||
# AndroidCastDeviceProvider.js
|
||||
component {7394f24c-dbc3-48c8-8a47-cd10169b7c6b} AndroidCastDeviceProvider.js
|
||||
contract @mozilla.org/presentation-device/android-cast-device-provider;1 {7394f24c-dbc3-48c8-8a47-cd10169b7c6b}
|
||||
category presentation-device-provider AndroidCastDeviceProvider @mozilla.org/presentation-device/android-cast-device-provider;1
|
|
@ -22,9 +22,12 @@ EXTRA_JS_MODULES.presentation += [
|
|||
'StateMachineHelper.jsm',
|
||||
]
|
||||
|
||||
# for TV 2.5 device backward capability
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
EXTRA_COMPONENTS += [
|
||||
# For android presentation device
|
||||
'AndroidCastDeviceProvider.js',
|
||||
'AndroidCastDeviceProvider.manifest',
|
||||
# for TV 2.5 device backward capability
|
||||
'LegacyPresentationControlService.js',
|
||||
'LegacyProviders.manifest',
|
||||
]
|
||||
|
|
|
@ -296,7 +296,7 @@ protected:
|
|||
char16_t mChar;
|
||||
|
||||
WSPoint()
|
||||
: mTextNode(0)
|
||||
: mTextNode(nullptr)
|
||||
, mOffset(0)
|
||||
, mChar(0)
|
||||
{}
|
||||
|
|
|
@ -105,8 +105,8 @@ skip-if(Android) needs-focus == 462758-grabbers-resizers.html 462758-grabbers-re
|
|||
needs-focus == spellcheck-superscript-1.html spellcheck-superscript-1-ref.html
|
||||
fails-if(Android) needs-focus != spellcheck-superscript-2.html spellcheck-superscript-2-ref.html # bug 783658
|
||||
fuzzy-if(skiaContent,1,3400) needs-focus pref(layout.accessiblecaret.enabled,false) pref(layout.accessiblecaret.enabled_on_touch,false) == 824080-1.html 824080-1-ref.html
|
||||
needs-focus pref(layout.accessiblecaret.enabled,false) pref(layout.accessiblecaret.enabled_on_touch,false) == 824080-2.html 824080-2-ref.html
|
||||
needs-focus pref(layout.accessiblecaret.enabled,false) pref(layout.accessiblecaret.enabled_on_touch,false) == 824080-3.html 824080-3-ref.html
|
||||
fuzzy-if(OSX,1,1) needs-focus pref(layout.accessiblecaret.enabled,false) pref(layout.accessiblecaret.enabled_on_touch,false) == 824080-2.html 824080-2-ref.html #Bug 1313253
|
||||
fuzzy-if(OSX,1,1) needs-focus pref(layout.accessiblecaret.enabled,false) pref(layout.accessiblecaret.enabled_on_touch,false) == 824080-3.html 824080-3-ref.html #Bug 1312951
|
||||
needs-focus != 824080-2.html 824080-3.html
|
||||
fuzzy-if(skiaContent,1,3200) needs-focus pref(layout.accessiblecaret.enabled,false) pref(layout.accessiblecaret.enabled_on_touch,false) == 824080-4.html 824080-4-ref.html
|
||||
fuzzy-if(skiaContent,2,1800) needs-focus pref(layout.accessiblecaret.enabled,false) pref(layout.accessiblecaret.enabled_on_touch,false) == 824080-5.html 824080-5-ref.html
|
||||
|
|
|
@ -19,7 +19,7 @@ NS_IMPL_ISUPPORTS(nsTransactionList, nsITransactionList)
|
|||
|
||||
nsTransactionList::nsTransactionList(nsITransactionManager *aTxnMgr, nsTransactionStack *aTxnStack)
|
||||
: mTxnStack(aTxnStack)
|
||||
, mTxnItem(0)
|
||||
, mTxnItem(nullptr)
|
||||
{
|
||||
if (aTxnMgr)
|
||||
mTxnMgr = do_GetWeakReference(aTxnMgr);
|
||||
|
@ -36,7 +36,7 @@ nsTransactionList::nsTransactionList(nsITransactionManager *aTxnMgr, nsTransacti
|
|||
nsTransactionList::~nsTransactionList()
|
||||
{
|
||||
mTxnStack = 0;
|
||||
mTxnItem = 0;
|
||||
mTxnItem = nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTransactionList::GetNumItems(int32_t *aNumItems)
|
||||
|
|
|
@ -1211,9 +1211,8 @@ TextureClient::CreateForYCbCr(KnowsCompositor* aAllocator,
|
|||
YUVColorSpace aYUVColorSpace,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
// The only reason we allow aAllocator to be null is for gtests
|
||||
MOZ_ASSERT(!aAllocator || aAllocator->GetLayersIPCActor()->IPCOpen());
|
||||
if (aAllocator && !aAllocator->GetLayersIPCActor()->IPCOpen()) {
|
||||
if (!aAllocator || !aAllocator->GetLayersIPCActor()->IPCOpen()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1229,7 +1228,7 @@ TextureClient::CreateForYCbCr(KnowsCompositor* aAllocator,
|
|||
}
|
||||
|
||||
return MakeAndAddRef<TextureClient>(data, aTextureFlags,
|
||||
aAllocator ? aAllocator->GetTextureForwarder() : nullptr);
|
||||
aAllocator->GetTextureForwarder());
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -1241,7 +1240,7 @@ TextureClient::CreateForYCbCrWithBufferSize(KnowsCompositor* aAllocator,
|
|||
{
|
||||
// also test the validity of aAllocator
|
||||
MOZ_ASSERT(!aAllocator || aAllocator->GetLayersIPCActor()->IPCOpen());
|
||||
if (aAllocator && !aAllocator->GetLayersIPCActor()->IPCOpen()) {
|
||||
if (!aAllocator || !aAllocator->GetLayersIPCActor()->IPCOpen()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1253,7 +1252,7 @@ TextureClient::CreateForYCbCrWithBufferSize(KnowsCompositor* aAllocator,
|
|||
}
|
||||
|
||||
return MakeAndAddRef<TextureClient>(data, aTextureFlags,
|
||||
aAllocator ? aAllocator->GetTextureForwarder() : 0);
|
||||
aAllocator->GetTextureForwarder());
|
||||
}
|
||||
|
||||
TextureClient::TextureClient(TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator)
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/Tools.h"
|
||||
#include "mozilla/layers/BufferTexture.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "mozilla/layers/BufferTexture.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxImageSurface.h"
|
||||
|
@ -266,7 +267,16 @@ TEST(Layers, TextureYCbCrSerialization) {
|
|||
clientData.mPicX = 0;
|
||||
clientData.mPicX = 0;
|
||||
|
||||
RefPtr<TextureClient> client = TextureClient::CreateForYCbCr(nullptr, clientData.mYSize, clientData.mCbCrSize,
|
||||
ImageBridgeChild::InitSameProcess();
|
||||
// wait until IPDL connection
|
||||
#ifdef XP_WIN
|
||||
Sleep(1);
|
||||
#else
|
||||
sleep(1);
|
||||
#endif
|
||||
RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
|
||||
|
||||
RefPtr<TextureClient> client = TextureClient::CreateForYCbCr(imageBridge, clientData.mYSize, clientData.mCbCrSize,
|
||||
StereoMode::MONO, YUVColorSpace::BT601,
|
||||
TextureFlags::DEALLOCATE_CLIENT);
|
||||
|
||||
|
|
|
@ -523,6 +523,7 @@ private:
|
|||
DECL_GFX_PREF(Live, "layers.transaction.warning-ms", LayerTransactionWarning, uint32_t, 200);
|
||||
DECL_GFX_PREF(Once, "layers.uniformity-info", UniformityInfo, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.use-image-offscreen-surfaces", UseImageOffscreenSurfaces, bool, true);
|
||||
DECL_GFX_PREF(Live, "layers.draw-mask-debug", DrawMaskLayer, bool, false);
|
||||
|
||||
DECL_GFX_PREF(Live, "layout.css.scroll-behavior.damping-ratio", ScrollBehaviorDampingRatio, float, 1.0f);
|
||||
DECL_GFX_PREF(Live, "layout.css.scroll-behavior.enabled", ScrollBehaviorEnabled, bool, true);
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ObjectWatcher::ObjectWatcher() : watch_(NULL) {
|
||||
ObjectWatcher::ObjectWatcher() : watch_(nullptr) {
|
||||
}
|
||||
|
||||
ObjectWatcher::~ObjectWatcher() {
|
||||
|
@ -99,7 +99,7 @@ bool ObjectWatcher::StopWatching() {
|
|||
// anything once it is run.
|
||||
watch_->watcher = NULL;
|
||||
|
||||
watch_ = NULL;
|
||||
watch_ = nullptr;
|
||||
|
||||
MessageLoop::current()->RemoveDestructionObserver(this);
|
||||
return true;
|
||||
|
|
|
@ -12,8 +12,8 @@ namespace base {
|
|||
|
||||
void BaseTimer_Helper::OrphanDelayedTask() {
|
||||
if (delayed_task_) {
|
||||
delayed_task_->timer_ = NULL;
|
||||
delayed_task_ = NULL;
|
||||
delayed_task_->timer_ = nullptr;
|
||||
delayed_task_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ class BaseTimer : public BaseTimer_Helper {
|
|||
// Task is old. So, if the Timer points to a different task, assume
|
||||
// that the Timer has already taken care of properly setting the task.
|
||||
if (self->delayed_task_ == this)
|
||||
self->delayed_task_ = NULL;
|
||||
self->delayed_task_ = nullptr;
|
||||
// By now the delayed_task_ in the Timer does not point to us anymore.
|
||||
// We should reset our own timer_ because the Timer can not do this
|
||||
// for us in its destructor.
|
||||
|
|
|
@ -7090,8 +7090,8 @@ bool nsDisplayMask::ShouldPaintOnMaskLayer(LayerManager* aManager)
|
|||
return false;
|
||||
}
|
||||
|
||||
nsSVGIntegrationUtils::MaskUsage maskUsage;
|
||||
nsSVGIntegrationUtils::DetermineMaskUsage(mFrame, mHandleOpacity, maskUsage);
|
||||
nsSVGUtils::MaskUsage maskUsage;
|
||||
nsSVGUtils::DetermineMaskUsage(mFrame, mHandleOpacity, maskUsage);
|
||||
|
||||
if (!maskUsage.shouldGenerateMaskLayer ||
|
||||
maskUsage.opacity != 1.0 || maskUsage.shouldApplyClipPath ||
|
||||
|
@ -7118,6 +7118,10 @@ bool nsDisplayMask::ShouldPaintOnMaskLayer(LayerManager* aManager)
|
|||
}
|
||||
}
|
||||
|
||||
if (gfxPrefs::DrawMaskLayer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ class AccessibleCaretCursorModeTestCase(MarionetteTestCase):
|
|||
el = self.marionette.find_element(By.ID, self._input_id)
|
||||
sel = SelectionManager(el)
|
||||
content_to_add = '!'
|
||||
target_content = sel.content + string.ascii_letters + content_to_add
|
||||
non_target_content = content_to_add + sel.content + string.ascii_letters
|
||||
|
||||
el.tap()
|
||||
sel.move_cursor_to_end()
|
||||
|
@ -184,10 +184,10 @@ class AccessibleCaretCursorModeTestCase(MarionetteTestCase):
|
|||
dest_x, dest_y = 0, 0
|
||||
self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()
|
||||
|
||||
# The content should be inserted at the end of the <input>.
|
||||
# The content should not be inserted at the front of the <input>.
|
||||
el.send_keys(content_to_add)
|
||||
|
||||
self.assertEqual(target_content, sel.content)
|
||||
self.assertNotEqual(non_target_content, sel.content)
|
||||
|
||||
@parameterized(_input_id, el_id=_input_id)
|
||||
@parameterized(_input_padding_id, el_id=_input_padding_id)
|
||||
|
|
|
@ -356,7 +356,7 @@ BlockReflowInput::GetFloatAvailableSpaceWithState(
|
|||
#ifdef DEBUG
|
||||
if (nsBlockFrame::gNoisyReflow) {
|
||||
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
||||
printf("GetAvailableSpace: band=%d,%d,%d,%d hasfloats=%d\n",
|
||||
printf("%s: band=%d,%d,%d,%d hasfloats=%d\n", __func__,
|
||||
result.mRect.IStart(wm), result.mRect.BStart(wm),
|
||||
result.mRect.ISize(wm), result.mRect.BSize(wm), result.mHasFloats);
|
||||
}
|
||||
|
@ -389,7 +389,7 @@ BlockReflowInput::GetFloatAvailableSpaceForBSize(
|
|||
#ifdef DEBUG
|
||||
if (nsBlockFrame::gNoisyReflow) {
|
||||
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
||||
printf("GetAvailableSpaceForHeight: space=%d,%d,%d,%d hasfloats=%d\n",
|
||||
printf("%s: space=%d,%d,%d,%d hasfloats=%d\n", __func__,
|
||||
result.mRect.IStart(wm), result.mRect.BStart(wm),
|
||||
result.mRect.ISize(wm), result.mRect.BSize(wm), result.mHasFloats);
|
||||
}
|
||||
|
@ -614,7 +614,7 @@ BlockReflowInput::AddFloat(nsLineLayout* aLineLayout,
|
|||
bool placed;
|
||||
|
||||
// Now place the float immediately if possible. Otherwise stash it
|
||||
// away in mPendingFloats and place it later.
|
||||
// away in mBelowCurrentLineFloats and place it later.
|
||||
// If one or more floats has already been pushed to the next line,
|
||||
// don't let this one go on the current line, since that would violate
|
||||
// float ordering.
|
||||
|
@ -628,7 +628,13 @@ BlockReflowInput::AddFloat(nsLineLayout* aLineLayout,
|
|||
if (placed) {
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
WritingMode wm = mReflowInput.GetWritingMode();
|
||||
nsFlowAreaRect floatAvailSpace = GetFloatAvailableSpace(mBCoord);
|
||||
// If we have mLineBSize, we are reflowing the line again due to
|
||||
// LineReflowStatus::RedoMoreFloats. We should use mLineBSize to query the
|
||||
// correct available space.
|
||||
nsFlowAreaRect floatAvailSpace =
|
||||
mLineBSize.isNothing()
|
||||
? GetFloatAvailableSpace(mBCoord)
|
||||
: GetFloatAvailableSpaceForBSize(mBCoord, mLineBSize.value(), nullptr);
|
||||
LogicalRect availSpace(wm, floatAvailSpace.mRect.IStart(wm), mBCoord,
|
||||
floatAvailSpace.mRect.ISize(wm),
|
||||
floatAvailSpace.mRect.BSize(wm));
|
||||
|
|
|
@ -376,6 +376,12 @@ public:
|
|||
// The amount of computed block-direction size "consumed" by previous-in-flows.
|
||||
nscoord mConsumedBSize;
|
||||
|
||||
// Cache the current line's BSize if nsBlockFrame::PlaceLine() fails to
|
||||
// place the line. When redoing the line, it will be used to query the
|
||||
// accurate float available space in AddFloat() and
|
||||
// nsBlockFrame::PlaceLine().
|
||||
mozilla::Maybe<nscoord> mLineBSize;
|
||||
|
||||
private:
|
||||
bool CanPlaceFloat(nscoord aFloatISize,
|
||||
const nsFlowAreaRect& aFloatAvailableSpace);
|
||||
|
|
|
@ -3765,7 +3765,8 @@ nsBlockFrame::ReflowInlineFrames(BlockReflowInput& aState,
|
|||
|
||||
LineReflowStatus lineReflowStatus;
|
||||
do {
|
||||
nscoord availableSpaceHeight = 0;
|
||||
nscoord availableSpaceBSize = 0;
|
||||
aState.mLineBSize.reset();
|
||||
do {
|
||||
bool allowPullUp = true;
|
||||
nsIFrame* forceBreakInFrame = nullptr;
|
||||
|
@ -3790,7 +3791,7 @@ nsBlockFrame::ReflowInlineFrames(BlockReflowInput& aState,
|
|||
lineLayout.ForceBreakAtPosition(forceBreakInFrame, forceBreakOffset);
|
||||
}
|
||||
DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
floatAvailableSpace, availableSpaceHeight,
|
||||
floatAvailableSpace, availableSpaceBSize,
|
||||
&floatManagerState, aKeepReflowGoing,
|
||||
&lineReflowStatus, allowPullUp);
|
||||
lineLayout.EndLineReflow();
|
||||
|
@ -3837,7 +3838,7 @@ nsBlockFrame::DoReflowInlineFrames(BlockReflowInput& aState,
|
|||
nsLineLayout& aLineLayout,
|
||||
LineIterator aLine,
|
||||
nsFlowAreaRect& aFloatAvailableSpace,
|
||||
nscoord& aAvailableSpaceHeight,
|
||||
nscoord& aAvailableSpaceBSize,
|
||||
nsFloatManager::SavedState*
|
||||
aFloatStateBeforeLine,
|
||||
bool* aKeepReflowGoing,
|
||||
|
@ -4044,7 +4045,7 @@ nsBlockFrame::DoReflowInlineFrames(BlockReflowInput& aState,
|
|||
// no point in placing the line.
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
||||
if (!PlaceLine(aState, aLineLayout, aLine, aFloatStateBeforeLine,
|
||||
aFloatAvailableSpace.mRect, aAvailableSpaceHeight,
|
||||
aFloatAvailableSpace.mRect, aAvailableSpaceBSize,
|
||||
aKeepReflowGoing)) {
|
||||
lineReflowStatus = LineReflowStatus::RedoMoreFloats;
|
||||
// PlaceLine already called GetAvailableSpaceForBSize for us.
|
||||
|
@ -4432,12 +4433,12 @@ nsBlockFrame::IsLastLine(BlockReflowInput& aState,
|
|||
|
||||
bool
|
||||
nsBlockFrame::PlaceLine(BlockReflowInput& aState,
|
||||
nsLineLayout& aLineLayout,
|
||||
LineIterator aLine,
|
||||
nsLineLayout& aLineLayout,
|
||||
LineIterator aLine,
|
||||
nsFloatManager::SavedState *aFloatStateBeforeLine,
|
||||
LogicalRect& aFloatAvailableSpace,
|
||||
nscoord& aAvailableSpaceHeight,
|
||||
bool* aKeepReflowGoing)
|
||||
LogicalRect& aFloatAvailableSpace,
|
||||
nscoord& aAvailableSpaceBSize,
|
||||
bool* aKeepReflowGoing)
|
||||
{
|
||||
// Trim extra white-space from the line before placing the frames
|
||||
aLineLayout.TrimTrailingWhiteSpace();
|
||||
|
@ -4469,30 +4470,66 @@ nsBlockFrame::PlaceLine(BlockReflowInput& aState,
|
|||
}
|
||||
aLineLayout.VerticalAlignLine();
|
||||
|
||||
// We want to compare to the available space that we would have had in
|
||||
// the line's height *before* we placed any floats in the line itself.
|
||||
// Floats that are in the line are handled during line reflow (and may
|
||||
// result in floats being pushed to below the line or (I HOPE???) in a
|
||||
// reflow with a forced break position).
|
||||
LogicalRect oldFloatAvailableSpace(aFloatAvailableSpace);
|
||||
// As we redo for floats, we can't reduce the amount of height we're
|
||||
// We want to consider the floats in the current line when determining
|
||||
// whether the float available space is shrunk. If mLineBSize doesn't
|
||||
// exist, we are in the first pass trying to place the line. Calling
|
||||
// GetFloatAvailableSpace() like we did in BlockReflowInput::AddFloat()
|
||||
// for UpdateBand().
|
||||
|
||||
// floatAvailableSpaceWithOldLineBSize is the float available space with
|
||||
// the old BSize, but including the floats that were added in this line.
|
||||
LogicalRect floatAvailableSpaceWithOldLineBSize =
|
||||
aState.mLineBSize.isNothing()
|
||||
? aState.GetFloatAvailableSpace(aLine->BStart()).mRect
|
||||
: aState.GetFloatAvailableSpaceForBSize(aLine->BStart(),
|
||||
aState.mLineBSize.value(),
|
||||
nullptr).mRect;
|
||||
|
||||
// As we redo for floats, we can't reduce the amount of BSize we're
|
||||
// checking.
|
||||
aAvailableSpaceHeight = std::max(aAvailableSpaceHeight, aLine->BSize());
|
||||
aFloatAvailableSpace =
|
||||
aAvailableSpaceBSize = std::max(aAvailableSpaceBSize, aLine->BSize());
|
||||
LogicalRect floatAvailableSpaceWithLineBSize =
|
||||
aState.GetFloatAvailableSpaceForBSize(aLine->BStart(),
|
||||
aAvailableSpaceHeight,
|
||||
aFloatStateBeforeLine).mRect;
|
||||
NS_ASSERTION(aFloatAvailableSpace.BStart(wm) ==
|
||||
oldFloatAvailableSpace.BStart(wm), "yikes");
|
||||
// Restore the height to the position of the next band.
|
||||
aFloatAvailableSpace.BSize(wm) = oldFloatAvailableSpace.BSize(wm);
|
||||
aAvailableSpaceBSize,
|
||||
nullptr).mRect;
|
||||
|
||||
// If the available space between the floats is smaller now that we
|
||||
// know the height, return false (and cause another pass with
|
||||
// LineReflowStatus::RedoMoreFloats). We ensure aAvailableSpaceHeight
|
||||
// know the BSize, return false (and cause another pass with
|
||||
// LineReflowStatus::RedoMoreFloats). We ensure aAvailableSpaceBSize
|
||||
// never decreases, which means that we can't reduce the set of floats
|
||||
// we intersect, which means that the available space cannot grow.
|
||||
if (AvailableSpaceShrunk(wm, oldFloatAvailableSpace, aFloatAvailableSpace,
|
||||
false)) {
|
||||
if (AvailableSpaceShrunk(wm, floatAvailableSpaceWithOldLineBSize,
|
||||
floatAvailableSpaceWithLineBSize, false)) {
|
||||
// Prepare data for redoing the line.
|
||||
aState.mLineBSize = Some(aLine->BSize());
|
||||
|
||||
// Since we want to redo the line, we update aFloatAvailableSpace by
|
||||
// using the aFloatStateBeforeLine, which is the float manager's state
|
||||
// before the line is placed.
|
||||
LogicalRect oldFloatAvailableSpace(aFloatAvailableSpace);
|
||||
aFloatAvailableSpace =
|
||||
aState.GetFloatAvailableSpaceForBSize(aLine->BStart(),
|
||||
aAvailableSpaceBSize,
|
||||
aFloatStateBeforeLine).mRect;
|
||||
NS_ASSERTION(aFloatAvailableSpace.BStart(wm) ==
|
||||
oldFloatAvailableSpace.BStart(wm), "yikes");
|
||||
// Restore the BSize to the position of the next band.
|
||||
aFloatAvailableSpace.BSize(wm) = oldFloatAvailableSpace.BSize(wm);
|
||||
|
||||
// Enforce both IStart() and IEnd() never move outwards to prevent
|
||||
// infinite grow-shrink loops.
|
||||
const nscoord iStartDiff =
|
||||
aFloatAvailableSpace.IStart(wm) - oldFloatAvailableSpace.IStart(wm);
|
||||
const nscoord iEndDiff =
|
||||
aFloatAvailableSpace.IEnd(wm) - oldFloatAvailableSpace.IEnd(wm);
|
||||
if (iStartDiff < 0) {
|
||||
aFloatAvailableSpace.IStart(wm) -= iStartDiff;
|
||||
aFloatAvailableSpace.ISize(wm) += iStartDiff;
|
||||
}
|
||||
if (iEndDiff > 0) {
|
||||
aFloatAvailableSpace.ISize(wm) -= iEndDiff;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -659,7 +659,7 @@ protected:
|
|||
LineIterator aLine,
|
||||
nsFloatManager::SavedState* aFloatStateBeforeLine,
|
||||
mozilla::LogicalRect& aFloatAvailableSpace, //in-out
|
||||
nscoord& aAvailableSpaceHeight, // in-out
|
||||
nscoord& aAvailableSpaceBSize, // in-out
|
||||
bool* aKeepReflowGoing);
|
||||
|
||||
/**
|
||||
|
@ -705,9 +705,8 @@ protected:
|
|||
nsLineLayout& aLineLayout,
|
||||
LineIterator aLine,
|
||||
nsFlowAreaRect& aFloatAvailableSpace,
|
||||
nscoord& aAvailableSpaceHeight,
|
||||
nsFloatManager::SavedState*
|
||||
aFloatStateBeforeLine,
|
||||
nscoord& aAvailableSpaceBSize,
|
||||
nsFloatManager::SavedState* aFloatStateBeforeLine,
|
||||
bool* aKeepReflowGoing,
|
||||
LineReflowStatus* aLineReflowStatus,
|
||||
bool aAllowPullUp);
|
||||
|
|
|
@ -1394,7 +1394,7 @@ fuzzy-if(skiaContent,1,17000) == 498228-1.xul 498228-1-ref.xul
|
|||
== 501257-1.xhtml 501257-1-ref.xhtml
|
||||
== 501627-1.html 501627-1-ref.html
|
||||
== 502288-1.html 502288-1-ref.html
|
||||
== 502447-1.html 502447-1-ref.html
|
||||
fuzzy-if(gtkWidget,1,2) == 502447-1.html 502447-1-ref.html #Bug 1315834
|
||||
== 502795-1.html 502795-1-ref.html
|
||||
== 502942-1.html 502942-1-ref.html
|
||||
== 503364-1a.html 503364-1-ref.html
|
||||
|
|
|
@ -20,6 +20,12 @@
|
|||
width: 200px;
|
||||
height: 100px;
|
||||
}
|
||||
div.tall {
|
||||
background-color: blue;
|
||||
border: 1px dotted purple;
|
||||
height: 1000px;
|
||||
width: 50px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function runTest() {
|
||||
|
@ -31,21 +37,11 @@
|
|||
<body onload="runTest();">
|
||||
<details>
|
||||
<summary id="summary">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
|
||||
minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
|
||||
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
|
||||
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
|
||||
sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
<div class="tall">
|
||||
</div>
|
||||
</summary>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
|
||||
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
|
||||
est laborum.
|
||||
<div class="tall">
|
||||
</div>
|
||||
</details>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -16,24 +16,21 @@
|
|||
width: 200px;
|
||||
height: 100px;
|
||||
}
|
||||
div.tall {
|
||||
background-color: blue;
|
||||
border: 1px dotted purple;
|
||||
height: 1000px;
|
||||
width: 50px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="details">
|
||||
<div id="summary">Lorem ipsum dolor sit amet, consectetur adipiscing elit,
|
||||
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
||||
enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
||||
aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit
|
||||
in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
|
||||
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
|
||||
officia deserunt mollit anim id est laborum.
|
||||
<div id="summary">
|
||||
<div class="tall">
|
||||
</div>
|
||||
</div>
|
||||
<div class="tall">
|
||||
</div>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
|
||||
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
|
||||
est laborum.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -20,24 +20,21 @@
|
|||
width: 200px;
|
||||
height: 100px;
|
||||
}
|
||||
div.tall {
|
||||
background-color: blue;
|
||||
border: 1px dotted purple;
|
||||
height: 1000px;
|
||||
width: 50px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<details open>
|
||||
<summary>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
|
||||
minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
|
||||
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
|
||||
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
|
||||
sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
<summary>
|
||||
<div class="tall">
|
||||
</div>
|
||||
</summary>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
|
||||
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
|
||||
est laborum.
|
||||
<div class="tall">
|
||||
</div>
|
||||
</details>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -95,7 +95,7 @@ fuzzy-if(gtkWidget,1,20) == mouse-click-overflow-auto-details.html overflow-auto
|
|||
== mouse-click-fixed-summary.html open-fixed-summary.html
|
||||
== mouse-click-twice-fixed-summary.html fixed-summary.html
|
||||
== mouse-click-float-details.html open-float-details.html
|
||||
== mouse-click-twice-float-details.html float-details.html
|
||||
fuzzy-if(gtkWidget,1,1) == mouse-click-twice-float-details.html float-details.html #Bug 1316430
|
||||
|
||||
# Dispatch keyboard event to summary
|
||||
== key-enter-single-summary.html open-single-summary.html
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
.container {
|
||||
position: relative;
|
||||
width: 250px;
|
||||
height: 300px;
|
||||
border: 1px solid blue;
|
||||
}
|
||||
|
||||
.float1 {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
height: 50px;
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.float2 {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
width: 180px;
|
||||
height: 50px;
|
||||
background-color: lightgreen;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
left: 180px;
|
||||
width: 30px;
|
||||
height: 80px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<div class="float1"></div>
|
||||
<div class="float2"></div>
|
||||
<div class="box"></div>
|
||||
</div>
|
||||
<p>The test pass if the inline blue box does not overlap any of the green float boxes.</p>
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
.container {
|
||||
width: 250px;
|
||||
height: 300px;
|
||||
border: 1px solid blue;
|
||||
}
|
||||
|
||||
.float1 {
|
||||
float: left;
|
||||
width: 100px;
|
||||
height: 50px;
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.float2 {
|
||||
float: left;
|
||||
width: 180px;
|
||||
height: 50px;
|
||||
background-color: lightgreen;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
height: 80px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<div class="float1"></div>
|
||||
<div class="float2"></div>
|
||||
<div class="box"></div>
|
||||
</div>
|
||||
<p>The test pass if the inline blue box does not overlap any of the green float boxes.</p>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
.container {
|
||||
position: relative;
|
||||
width: 250px;
|
||||
height: 300px;
|
||||
border: 1px solid blue;
|
||||
}
|
||||
|
||||
.float1 {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
height: 50px;
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.float2 {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 70px;
|
||||
width: 180px;
|
||||
height: 50px;
|
||||
background-color: lightgreen;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
width: 30px;
|
||||
height: 80px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<div class="float1"></div>
|
||||
<div class="float2"></div>
|
||||
<div class="box"></div>
|
||||
</div>
|
||||
<p>The test pass if the inline blue box does not overlap any of the green float boxes.</p>
|
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
.container {
|
||||
width: 250px;
|
||||
height: 300px;
|
||||
border: 1px solid blue;
|
||||
}
|
||||
|
||||
.float1 {
|
||||
float: left;
|
||||
width: 100px;
|
||||
height: 50px;
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.float2 {
|
||||
float: right;
|
||||
width: 180px;
|
||||
height: 50px;
|
||||
background-color: lightgreen;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
height: 80px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<div class="float1"></div>
|
||||
<div class="float2"></div>
|
||||
<div class="box"></div>
|
||||
</div>
|
||||
<p>The test pass if the inline blue box does not overlap any of the green float boxes.</p>
|
|
@ -10,7 +10,7 @@ fuzzy-if(gtkWidget,1,10) == float-outside-block-push.html float-outside-block-pu
|
|||
== relative-float-2.html relative-float-2-ref.html
|
||||
== zero-height-float-base.html zero-height-float-ref.html
|
||||
fails == zero-height-float.html zero-height-float-ref.html # bug 81710
|
||||
fails == 345369-1.html 345369-1-ref.html
|
||||
== 345369-1.html 345369-1-ref.html
|
||||
fails == 345369-2.html 345369-2-ref.html
|
||||
== 345369-3.html 345369-3-ref.html
|
||||
== 345369-4.html 345369-4-ref.html
|
||||
|
@ -24,6 +24,8 @@ fails == 345369-2.html 345369-2-ref.html
|
|||
== 1260031-1.html?display:table 1260031-1-ref.html
|
||||
== 1260031-1.html?display:table-cell 1260031-1-ref.html
|
||||
== 1260031-1.html?overflow:hidden 1260031-1-ref.html
|
||||
== 1291110-1.html 1291110-1-ref.html
|
||||
== 1291110-2.html 1291110-2-ref.html
|
||||
== float-in-rtl-1a.html float-in-rtl-1-ref.html
|
||||
fuzzy-if(skiaContent,1,27000) == float-in-rtl-1b.html float-in-rtl-1-ref.html
|
||||
fuzzy-if(skiaContent,1,27000) == float-in-rtl-1c.html float-in-rtl-1-ref.html
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<html class="reftest-wait">
|
||||
<script>
|
||||
/* this test shouldn't need reftest-wait, but if the reftest snapshot is triggered before we've painted,
|
||||
* then we might not get a chance to invalidate the -moz-element div in time
|
||||
* See Bug 1283302
|
||||
*/
|
||||
window.addEventListener("MozReftestInvalidate", endTest);
|
||||
|
||||
function endTest() {
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
<body>
|
||||
<div id="A" style="background:url(repeatable-diagonal-gradient.png?1234); width:100px; height:100px"></div>
|
||||
<div style="background:-moz-element(#A); width:100px; height:100px;"></div>
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Masking: clip-path in SVG mask</title>
|
||||
<link rel="author" title="CJ Ku" href="mailto:cku@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
|
||||
<link rel="help" href="https://www.w3.org/TR/css-masking-1/#the-mask-image">
|
||||
<link rel="match" href="mask-image-3-ref.html">
|
||||
<meta name="assert" content="Test checks whether clip-path in SVG mask works correctly or not.">
|
||||
<svg height="0">
|
||||
<mask id="mask1" x="0" y="0" width="1" height="1" >
|
||||
<rect x="0" y="0" width="50" height="50" style="stroke:none; fill: #ffffff"/>
|
||||
</mask>
|
||||
<mask id="mask2" x="0" y="0" width="1" height="1" >
|
||||
<rect x="25" y="25" width="50" height="50" style="stroke:none; fill: #ffffff" clip-path="circle(50% at 50% 50%)"/>
|
||||
</mask>
|
||||
</svg>
|
||||
<style type="text/css">
|
||||
div {
|
||||
background-color: purple;
|
||||
mask-image: url(#mask1), url(#mask2);
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div></div>
|
||||
</body>
|
||||
</html>
|
|
@ -26,6 +26,7 @@ fuzzy-if(skiaContent||winWidget,1,43) == mask-image-3d.html mask-image-3-ref.htm
|
|||
== mask-image-3e.html mask-image-3-ref.html
|
||||
fuzzy-if(skiaContent,50,50) == mask-image-3f.html mask-image-3-ref.html
|
||||
== mask-image-3g.html mask-image-3-ref.html
|
||||
pref(layout.css.clip-path-shapes.enabled,true) == mask-image-3h.html mask-image-3-ref.html
|
||||
== mask-image-4a.html blank.html
|
||||
== mask-image-4b.html blank.html
|
||||
== mask-image-5.html mask-image-5-ref.html
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
|
||||
<head>
|
||||
<title>CSS Test: Min/Max Height and Width Constraints on Replaced Elements with Box-Sizing</title>
|
||||
<link href="http://fantasai.inkedblade.net/contact" title="Elika J. Etemad" rel="author"></link>
|
||||
|
@ -131,6 +131,17 @@
|
|||
}
|
||||
</style>
|
||||
</head>
|
||||
<script>
|
||||
/* this test shouldn't need reftest-wait, but if the reftest snapshot is triggered before we've painted,
|
||||
* for img5 the right 1/3rd of the element simply isn't painted.
|
||||
* See Bug 1283302
|
||||
*/
|
||||
window.addEventListener("MozReftestInvalidate", endTest);
|
||||
|
||||
function endTest() {
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
<body>
|
||||
<div>All rectangles should be the same size.</div>
|
||||
<p><img id="img0" class="with-padding" src="support/replaced-min-max.png" alt="FAIL" title="Test 0"></img></p>
|
||||
|
|
|
@ -1815,6 +1815,10 @@ Loader::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus)
|
|||
{
|
||||
LOG(("css::Loader::SheetComplete"));
|
||||
|
||||
if (aLoadData->mSheet->IsServo() && NS_FAILED(aStatus)) {
|
||||
aLoadData->mSheet->AsServo()->LoadFailed();
|
||||
}
|
||||
|
||||
// 8 is probably big enough for all our common cases. It's not likely that
|
||||
// imports will nest more than 8 deep, and multiple sheets with the same URI
|
||||
// are rare.
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
SERVO_BINDING_FUNC(Servo_Node_ClearNodeData, void, RawGeckoNodeBorrowed node)
|
||||
|
||||
// Styleset and Stylesheet management
|
||||
SERVO_BINDING_FUNC(Servo_StyleSheet_Empty, RawServoStyleSheetStrong,
|
||||
mozilla::css::SheetParsingMode parsing_mode)
|
||||
SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetStrong,
|
||||
const nsACString* data,
|
||||
mozilla::css::SheetParsingMode parsing_mode,
|
||||
|
|
|
@ -81,6 +81,12 @@ ServoStyleSheet::ParseSheet(const nsAString& aInput,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSheet::LoadFailed()
|
||||
{
|
||||
mSheet = Servo_StyleSheet_Empty(mParsingMode).Consume();
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSheet::DropSheet()
|
||||
{
|
||||
|
|
|
@ -40,6 +40,13 @@ public:
|
|||
nsIPrincipal* aSheetPrincipal,
|
||||
uint32_t aLineNumber);
|
||||
|
||||
/**
|
||||
* Called instead of ParseSheet to initialize the Servo stylesheet object
|
||||
* for a failed load. Either ParseSheet or LoadFailed must be called before
|
||||
* adding a ServoStyleSheet to a ServoStyleSet.
|
||||
*/
|
||||
void LoadFailed();
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -576,19 +576,6 @@ CreateAndPaintMaskSurface(const PaintFramesParams& aParams,
|
|||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
static float
|
||||
ComputeOpacity(nsIFrame* aFrame, bool aHandleOpacity)
|
||||
{
|
||||
float opacity = aFrame->StyleEffects()->mOpacity;
|
||||
|
||||
if (opacity != 1.0f &&
|
||||
(nsSVGUtils::CanOptimizeOpacity(aFrame) || !aHandleOpacity)) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return opacity;
|
||||
}
|
||||
|
||||
static bool
|
||||
ValidateSVGFrame(nsIFrame* aFrame)
|
||||
{
|
||||
|
@ -685,72 +672,6 @@ SetupContextMatrix(nsIFrame* aFrame, const PaintFramesParams& aParams,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGIntegrationUtils::DetermineMaskUsage(nsIFrame* aFrame,
|
||||
bool aHandleOpacity,
|
||||
MaskUsage& aUsage)
|
||||
{
|
||||
aUsage.opacity = ComputeOpacity(aFrame, aHandleOpacity);
|
||||
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
|
||||
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
|
||||
|
||||
nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
|
||||
|
||||
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
|
||||
// For a HTML doc:
|
||||
// According to css-masking spec, always create a mask surface when we
|
||||
// have any item in maskFrame even if all of those items are
|
||||
// non-resolvable <mask-sources> or <images>, we still need to create a
|
||||
// transparent black mask layer under this condition.
|
||||
// For a SVG doc:
|
||||
// SVG 1.1 say that if we fail to resolve a mask, we should draw the
|
||||
// object unmasked.
|
||||
aUsage.shouldGenerateMaskLayer =
|
||||
(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)
|
||||
? maskFrames.Length() == 1 && maskFrames[0]
|
||||
: maskFrames.Length() > 0;
|
||||
#else
|
||||
// Since we do not support image mask so far, we should treat any
|
||||
// unresolvable mask as no mask. Otherwise, any object with a valid image
|
||||
// mask, e.g. url("xxx.png"), will become invisible just because we can not
|
||||
// handle image mask correctly. (See bug 1294171)
|
||||
aUsage.shouldGenerateMaskLayer = maskFrames.Length() == 1 && maskFrames[0];
|
||||
#endif
|
||||
|
||||
bool isOK = effectProperties.HasNoFilterOrHasValidFilter();
|
||||
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
|
||||
MOZ_ASSERT_IF(clipPathFrame,
|
||||
svgReset->mClipPath.GetType() == StyleShapeSourceType::URL);
|
||||
|
||||
switch (svgReset->mClipPath.GetType()) {
|
||||
case StyleShapeSourceType::URL:
|
||||
if (clipPathFrame) {
|
||||
if (clipPathFrame->IsTrivial()) {
|
||||
aUsage.shouldApplyClipPath = true;
|
||||
} else {
|
||||
aUsage.shouldGenerateClipMaskLayer = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case StyleShapeSourceType::Shape:
|
||||
case StyleShapeSourceType::Box:
|
||||
aUsage.shouldApplyBasicShape = true;
|
||||
break;
|
||||
case StyleShapeSourceType::None:
|
||||
MOZ_ASSERT(!aUsage.shouldGenerateClipMaskLayer &&
|
||||
!aUsage.shouldApplyClipPath && !aUsage.shouldApplyBasicShape);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unsupported clip-path type.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGIntegrationUtils::IsMaskResourceReady(nsIFrame* aFrame)
|
||||
{
|
||||
|
@ -780,8 +701,9 @@ nsSVGIntegrationUtils::IsMaskResourceReady(nsIFrame* aFrame)
|
|||
DrawResult
|
||||
nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
|
||||
{
|
||||
MaskUsage maskUsage;
|
||||
DetermineMaskUsage(aParams.frame, aParams.handleOpacity, maskUsage);
|
||||
nsSVGUtils::MaskUsage maskUsage;
|
||||
nsSVGUtils::DetermineMaskUsage(aParams.frame, aParams.handleOpacity,
|
||||
maskUsage);
|
||||
MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer);
|
||||
|
||||
nsIFrame* frame = aParams.frame;
|
||||
|
@ -841,8 +763,9 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
return result;
|
||||
}
|
||||
|
||||
MaskUsage maskUsage;
|
||||
DetermineMaskUsage(aParams.frame, aParams.handleOpacity, maskUsage);
|
||||
nsSVGUtils::MaskUsage maskUsage;
|
||||
nsSVGUtils::DetermineMaskUsage(aParams.frame, aParams.handleOpacity,
|
||||
maskUsage);
|
||||
|
||||
if (maskUsage.opacity == 0.0f) {
|
||||
return DrawResult::SUCCESS;
|
||||
|
@ -971,6 +894,18 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
aParams.builder);
|
||||
basic->SetTarget(oldCtx);
|
||||
|
||||
if (gfxPrefs::DrawMaskLayer()) {
|
||||
gfxContextAutoSaveRestore saver(&context);
|
||||
|
||||
context.NewPath();
|
||||
gfxRect drawingRect =
|
||||
nsLayoutUtils::RectToGfxRect(aParams.borderArea,
|
||||
frame->PresContext()->AppUnitsPerDevPixel());
|
||||
context.Rectangle(drawingRect, true);
|
||||
context.SetColor(Color(0.0, 1.0, 0.0, 1.0));
|
||||
context.Fill();
|
||||
}
|
||||
|
||||
if (maskUsage.shouldApplyClipPath || maskUsage.shouldApplyBasicShape) {
|
||||
context.PopClip();
|
||||
}
|
||||
|
@ -995,7 +930,7 @@ nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams)
|
|||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
float opacity = ComputeOpacity(frame, aParams.handleOpacity);
|
||||
float opacity = nsSVGUtils::ComputeOpacity(frame, aParams.handleOpacity);
|
||||
if (opacity == 0.0f) {
|
||||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
|
|
@ -167,22 +167,6 @@ public:
|
|||
static DrawResult
|
||||
PaintMask(const PaintFramesParams& aParams);
|
||||
|
||||
struct MaskUsage {
|
||||
bool shouldGenerateMaskLayer;
|
||||
bool shouldGenerateClipMaskLayer;
|
||||
bool shouldApplyClipPath;
|
||||
bool shouldApplyBasicShape;
|
||||
float opacity;
|
||||
|
||||
MaskUsage()
|
||||
: shouldGenerateMaskLayer(false), shouldGenerateClipMaskLayer(false),
|
||||
shouldApplyClipPath(false), shouldApplyBasicShape(false), opacity(0.0)
|
||||
{ }
|
||||
};
|
||||
|
||||
static void
|
||||
DetermineMaskUsage(nsIFrame* aFrame, bool aHandleOpacity, MaskUsage& aUsage);
|
||||
|
||||
/**
|
||||
* Return true if all the mask resource of aFrame are ready.
|
||||
*/
|
||||
|
|
|
@ -486,6 +486,139 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
float
|
||||
nsSVGUtils::ComputeOpacity(nsIFrame* aFrame, bool aHandleOpacity)
|
||||
{
|
||||
float opacity = aFrame->StyleEffects()->mOpacity;
|
||||
|
||||
if (opacity != 1.0f &&
|
||||
(nsSVGUtils::CanOptimizeOpacity(aFrame) || !aHandleOpacity)) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return opacity;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGUtils::DetermineMaskUsage(nsIFrame* aFrame, bool aHandleOpacity,
|
||||
MaskUsage& aUsage)
|
||||
{
|
||||
aUsage.opacity = ComputeOpacity(aFrame, aHandleOpacity);
|
||||
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
|
||||
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
|
||||
|
||||
nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
|
||||
|
||||
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
|
||||
// For a HTML doc:
|
||||
// According to css-masking spec, always create a mask surface when we
|
||||
// have any item in maskFrame even if all of those items are
|
||||
// non-resolvable <mask-sources> or <images>, we still need to create a
|
||||
// transparent black mask layer under this condition.
|
||||
// For a SVG doc:
|
||||
// SVG 1.1 say that if we fail to resolve a mask, we should draw the
|
||||
// object unmasked.
|
||||
aUsage.shouldGenerateMaskLayer =
|
||||
(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)
|
||||
? maskFrames.Length() == 1 && maskFrames[0]
|
||||
: maskFrames.Length() > 0;
|
||||
#else
|
||||
// Since we do not support image mask so far, we should treat any
|
||||
// unresolvable mask as no mask. Otherwise, any object with a valid image
|
||||
// mask, e.g. url("xxx.png"), will become invisible just because we can not
|
||||
// handle image mask correctly. (See bug 1294171)
|
||||
aUsage.shouldGenerateMaskLayer = maskFrames.Length() == 1 && maskFrames[0];
|
||||
#endif
|
||||
|
||||
bool isOK = effectProperties.HasNoFilterOrHasValidFilter();
|
||||
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
|
||||
MOZ_ASSERT_IF(clipPathFrame,
|
||||
svgReset->mClipPath.GetType() == StyleShapeSourceType::URL);
|
||||
|
||||
switch (svgReset->mClipPath.GetType()) {
|
||||
case StyleShapeSourceType::URL:
|
||||
if (clipPathFrame) {
|
||||
if (clipPathFrame->IsTrivial()) {
|
||||
aUsage.shouldApplyClipPath = true;
|
||||
} else {
|
||||
aUsage.shouldGenerateClipMaskLayer = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case StyleShapeSourceType::Shape:
|
||||
case StyleShapeSourceType::Box:
|
||||
aUsage.shouldApplyBasicShape = true;
|
||||
break;
|
||||
case StyleShapeSourceType::None:
|
||||
MOZ_ASSERT(!aUsage.shouldGenerateClipMaskLayer &&
|
||||
!aUsage.shouldApplyClipPath && !aUsage.shouldApplyBasicShape);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unsupported clip-path type.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static IntRect
|
||||
ComputeClipExtsInDeviceSpace(gfxContext& aCtx)
|
||||
{
|
||||
gfxContextMatrixAutoSaveRestore matRestore(&aCtx);
|
||||
|
||||
// Get the clip extents in device space.
|
||||
aCtx.SetMatrix(gfxMatrix());
|
||||
gfxRect clippedFrameSurfaceRect = aCtx.GetClipExtents();
|
||||
clippedFrameSurfaceRect.RoundOut();
|
||||
|
||||
IntRect result;
|
||||
ToRect(clippedFrameSurfaceRect).ToIntRect(&result);
|
||||
return mozilla::gfx::Factory::CheckSurfaceSize(result.Size()) ? result
|
||||
: IntRect();
|
||||
}
|
||||
|
||||
static already_AddRefed<gfxContext>
|
||||
CreateBlendTarget(gfxContext* aContext, IntPoint& aTargetOffset)
|
||||
{
|
||||
// Create a temporary context to draw to so we can blend it back with
|
||||
// another operator.
|
||||
IntRect drawRect = ComputeClipExtsInDeviceSpace(*aContext);
|
||||
|
||||
RefPtr<DrawTarget> targetDT =
|
||||
aContext->GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(),
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
if (!targetDT || !targetDT->IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<gfxContext> target = gfxContext::CreateOrNull(targetDT);
|
||||
MOZ_ASSERT(target); // already checked the draw target above
|
||||
target->SetMatrix(aContext->CurrentMatrix() *
|
||||
gfxMatrix::Translation(-drawRect.TopLeft()));
|
||||
aTargetOffset = drawRect.TopLeft();
|
||||
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
static void
|
||||
BlendToTarget(nsIFrame* aFrame, gfxContext* aSource, gfxContext* aTarget,
|
||||
const IntPoint& aTargetOffset)
|
||||
{
|
||||
MOZ_ASSERT(aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL);
|
||||
|
||||
RefPtr<DrawTarget> targetDT = aTarget->GetDrawTarget();
|
||||
RefPtr<SourceSurface> targetSurf = targetDT->Snapshot();
|
||||
|
||||
gfxContextAutoSaveRestore save(aSource);
|
||||
aSource->SetMatrix(gfxMatrix()); // This will be restored right after.
|
||||
RefPtr<gfxPattern> pattern = new gfxPattern(targetSurf, Matrix::Translation(aTargetOffset.x, aTargetOffset.y));
|
||||
aSource->SetPattern(pattern);
|
||||
aSource->Paint();
|
||||
}
|
||||
|
||||
DrawResult
|
||||
nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame,
|
||||
gfxContext& aContext,
|
||||
|
@ -502,9 +635,11 @@ nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame,
|
|||
if (!svgChildFrame)
|
||||
return DrawResult::SUCCESS;
|
||||
|
||||
float opacity = aFrame->StyleEffects()->mOpacity;
|
||||
if (opacity == 0.0f)
|
||||
MaskUsage maskUsage;
|
||||
DetermineMaskUsage(aFrame, true, maskUsage);
|
||||
if (maskUsage.opacity == 0.0f) {
|
||||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
const nsIContent* content = aFrame->GetContent();
|
||||
if (content->IsSVGElement() &&
|
||||
|
@ -512,14 +647,6 @@ nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame,
|
|||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
/* Properties are added lazily and may have been removed by a restyle,
|
||||
so make sure all applicable ones are set again. */
|
||||
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(aFrame);
|
||||
|
||||
bool isOK = effectProperties.HasNoFilterOrHasValidFilter();
|
||||
|
||||
if (aDirtyRect &&
|
||||
!(aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
|
||||
// Here we convert aFrame's paint bounds to outer-<svg> device space,
|
||||
|
@ -566,92 +693,82 @@ nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame,
|
|||
*
|
||||
* + Use cairo's clipPath when representable natively (single object
|
||||
* clip region).
|
||||
*
|
||||
*f
|
||||
* + Merge opacity and masking if both used together.
|
||||
*/
|
||||
|
||||
if (opacity != 1.0f && CanOptimizeOpacity(aFrame))
|
||||
opacity = 1.0f;
|
||||
|
||||
DrawTarget* drawTarget = aContext.GetDrawTarget();
|
||||
bool complexEffects = false;
|
||||
|
||||
/* Properties are added lazily and may have been removed by a restyle,
|
||||
so make sure all applicable ones are set again. */
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(aFrame);
|
||||
bool isOK = effectProperties.HasNoFilterOrHasValidFilter();
|
||||
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
|
||||
nsSVGMaskFrame *maskFrame = effectProperties.GetFirstMaskFrame(&isOK);
|
||||
|
||||
bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true;
|
||||
|
||||
if (!isOK) {
|
||||
// Some resource is invalid. We shouldn't paint anything.
|
||||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
// These are used if we require a temporary surface for a custom blend mode.
|
||||
RefPtr<gfxContext> target = &aContext;
|
||||
// Clip the source context first, so that we can generate a smaller temporary
|
||||
// surface. (Since we will clip this context in SetupContextMatrix, a pair
|
||||
// of save/restore is needed.)
|
||||
aContext.Save();
|
||||
if (!(aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
|
||||
// aFrame has a valid visual overflow rect, so clip to it before calling
|
||||
// PushGroup() to minimize the size of the surfaces we'll composite:
|
||||
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&aContext);
|
||||
aContext.Multiply(aTransform);
|
||||
nsRect overflowRect = aFrame->GetVisualOverflowRectRelativeToSelf();
|
||||
if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) ||
|
||||
aFrame->IsSVGText()) {
|
||||
// Unlike containers, leaf frames do not include GetPosition() in
|
||||
// GetCanvasTM().
|
||||
overflowRect = overflowRect + aFrame->GetPosition();
|
||||
}
|
||||
aContext.Clip(NSRectToSnappedRect(overflowRect,
|
||||
aFrame->PresContext()->AppUnitsPerDevPixel(),
|
||||
*aContext.GetDrawTarget()));
|
||||
}
|
||||
IntPoint targetOffset;
|
||||
RefPtr<gfxContext> target =
|
||||
(aFrame->StyleEffects()->mMixBlendMode == NS_STYLE_BLEND_NORMAL)
|
||||
? RefPtr<gfxContext>(&aContext).forget()
|
||||
: CreateBlendTarget(&aContext, targetOffset);
|
||||
aContext.Restore();
|
||||
|
||||
if (!target) {
|
||||
return DrawResult::TEMPORARY_ERROR;
|
||||
}
|
||||
|
||||
/* Check if we need to do additional operations on this child's
|
||||
* rendering, which necessitates rendering into another surface. */
|
||||
if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)
|
||||
|| aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
complexEffects = true;
|
||||
bool shouldGenerateMask = (maskUsage.opacity != 1.0f ||
|
||||
maskUsage.shouldGenerateClipMaskLayer ||
|
||||
maskUsage.shouldGenerateMaskLayer ||
|
||||
aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL);
|
||||
|
||||
if (shouldGenerateMask) {
|
||||
Matrix maskTransform;
|
||||
RefPtr<SourceSurface> maskSurface =
|
||||
maskFrame ? maskFrame->GetMaskForMaskedFrame(&aContext,
|
||||
aFrame, aTransform, opacity, &maskTransform)
|
||||
: nullptr;
|
||||
RefPtr<SourceSurface> maskSurface;
|
||||
|
||||
if (maskFrame && !maskSurface) {
|
||||
// Entire surface is clipped out.
|
||||
return DrawResult::SUCCESS;
|
||||
if (maskUsage.shouldGenerateMaskLayer) {
|
||||
maskSurface =
|
||||
maskFrame->GetMaskForMaskedFrame(&aContext, aFrame, aTransform,
|
||||
maskUsage.opacity, &maskTransform);
|
||||
|
||||
if (!maskSurface) {
|
||||
// Entire surface is clipped out.
|
||||
return DrawResult::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
aContext.Save();
|
||||
if (!(aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
|
||||
// aFrame has a valid visual overflow rect, so clip to it before calling
|
||||
// PushGroup() to minimize the size of the surfaces we'll composite:
|
||||
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&aContext);
|
||||
aContext.Multiply(aTransform);
|
||||
nsRect overflowRect = aFrame->GetVisualOverflowRectRelativeToSelf();
|
||||
if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) ||
|
||||
aFrame->IsSVGText()) {
|
||||
// Unlike containers, leaf frames do not include GetPosition() in
|
||||
// GetCanvasTM().
|
||||
overflowRect = overflowRect + aFrame->GetPosition();
|
||||
}
|
||||
aContext.Clip(NSRectToSnappedRect(overflowRect,
|
||||
aFrame->PresContext()->AppUnitsPerDevPixel(),
|
||||
*drawTarget));
|
||||
}
|
||||
|
||||
if (aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
// Create a temporary context to draw to so we can blend it back with
|
||||
// another operator.
|
||||
gfxRect clipRect;
|
||||
{
|
||||
gfxContextMatrixAutoSaveRestore matRestore(&aContext);
|
||||
|
||||
aContext.SetMatrix(gfxMatrix());
|
||||
clipRect = aContext.GetClipExtents();
|
||||
}
|
||||
|
||||
IntRect drawRect = RoundedOut(ToRect(clipRect));
|
||||
|
||||
RefPtr<DrawTarget> targetDT = aContext.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(), SurfaceFormat::B8G8R8A8);
|
||||
target = gfxContext::CreateOrNull(targetDT);
|
||||
if (!target) {
|
||||
gfxDevCrash(LogReason::InvalidContext) << "SVGPaintWithEffects context problem " << gfx::hexa(targetDT);
|
||||
return DrawResult::TEMPORARY_ERROR;
|
||||
}
|
||||
target->SetMatrix(aContext.CurrentMatrix() * gfxMatrix::Translation(-drawRect.TopLeft()));
|
||||
targetOffset = drawRect.TopLeft();
|
||||
}
|
||||
|
||||
if (clipPathFrame && !isTrivialClip) {
|
||||
if (maskUsage.shouldGenerateClipMaskLayer) {
|
||||
Matrix clippedMaskTransform;
|
||||
RefPtr<SourceSurface> clipMaskSurface = clipPathFrame->GetClipMask(aContext, aFrame, aTransform,
|
||||
&clippedMaskTransform, maskSurface, maskTransform);
|
||||
RefPtr<SourceSurface> clipMaskSurface =
|
||||
clipPathFrame->GetClipMask(aContext, aFrame, aTransform,
|
||||
&clippedMaskTransform, maskSurface,
|
||||
maskTransform);
|
||||
|
||||
if (clipMaskSurface) {
|
||||
maskSurface = clipMaskSurface;
|
||||
|
@ -659,21 +776,22 @@ nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame,
|
|||
}
|
||||
}
|
||||
|
||||
if (maskFrame) {
|
||||
target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, 1.0,
|
||||
maskSurface, maskTransform);
|
||||
} else if (opacity != 1.0f || (clipPathFrame && !isTrivialClip)) {
|
||||
target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity,
|
||||
maskSurface, maskTransform);
|
||||
}
|
||||
// SVG mask multiply opacity into maskSurface already, so we do not bother
|
||||
// to apply opacity again.
|
||||
float opacity = maskFrame ? 1.0 : maskUsage.opacity;
|
||||
target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity,
|
||||
maskSurface, maskTransform);
|
||||
}
|
||||
|
||||
/* If this frame has only a trivial clipPath, set up cairo's clipping now so
|
||||
* we can just do normal painting and get it clipped appropriately.
|
||||
*/
|
||||
if (clipPathFrame && isTrivialClip) {
|
||||
aContext.Save();
|
||||
clipPathFrame->ApplyClipPath(aContext, aFrame, aTransform);
|
||||
if (maskUsage.shouldApplyClipPath || maskUsage.shouldApplyBasicShape) {
|
||||
if (maskUsage.shouldApplyClipPath) {
|
||||
clipPathFrame->ApplyClipPath(aContext, aFrame, aTransform);
|
||||
} else {
|
||||
nsCSSClipPathInstance::ApplyBasicShapeClip(aContext, aFrame);
|
||||
}
|
||||
}
|
||||
|
||||
DrawResult result = DrawResult::SUCCESS;
|
||||
|
@ -708,30 +826,19 @@ nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame,
|
|||
result = svgChildFrame->PaintSVG(*target, aTransform, aDirtyRect);
|
||||
}
|
||||
|
||||
if (clipPathFrame && isTrivialClip) {
|
||||
aContext.Restore();
|
||||
if (maskUsage.shouldApplyClipPath || maskUsage.shouldApplyBasicShape) {
|
||||
aContext.PopClip();
|
||||
}
|
||||
|
||||
/* No more effects, we're done. */
|
||||
if (!complexEffects)
|
||||
return result;
|
||||
|
||||
if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
|
||||
if (shouldGenerateMask) {
|
||||
target->PopGroupAndBlend();
|
||||
}
|
||||
|
||||
if (aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
RefPtr<DrawTarget> targetDT = target->GetDrawTarget();
|
||||
target = nullptr;
|
||||
RefPtr<SourceSurface> targetSurf = targetDT->Snapshot();
|
||||
|
||||
aContext.SetMatrix(gfxMatrix()); // This will be restored right after.
|
||||
RefPtr<gfxPattern> pattern = new gfxPattern(targetSurf, Matrix::Translation(targetOffset.x, targetOffset.y));
|
||||
aContext.SetPattern(pattern);
|
||||
aContext.Paint();
|
||||
MOZ_ASSERT(target != &aContext);
|
||||
BlendToTarget(aFrame, &aContext, target, targetOffset);
|
||||
}
|
||||
|
||||
aContext.Restore();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -576,6 +576,25 @@ public:
|
|||
ToCanvasBounds(const gfxRect &aUserspaceRect,
|
||||
const gfxMatrix &aToCanvas,
|
||||
const nsPresContext *presContext);
|
||||
|
||||
struct MaskUsage {
|
||||
bool shouldGenerateMaskLayer;
|
||||
bool shouldGenerateClipMaskLayer;
|
||||
bool shouldApplyClipPath;
|
||||
bool shouldApplyBasicShape;
|
||||
float opacity;
|
||||
|
||||
MaskUsage()
|
||||
: shouldGenerateMaskLayer(false), shouldGenerateClipMaskLayer(false),
|
||||
shouldApplyClipPath(false), shouldApplyBasicShape(false), opacity(0.0)
|
||||
{ }
|
||||
};
|
||||
|
||||
static void
|
||||
DetermineMaskUsage(nsIFrame* aFrame, bool aHandleOpacity, MaskUsage& aUsage);
|
||||
|
||||
static float
|
||||
ComputeOpacity(nsIFrame* aFrame, bool aHandleOpacity);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
// Constructors
|
||||
|
||||
RefPtr()
|
||||
: mRawPtr(0)
|
||||
: mRawPtr(nullptr)
|
||||
// default constructor
|
||||
{
|
||||
}
|
||||
|
@ -112,6 +112,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
MOZ_IMPLICIT RefPtr(decltype(nullptr))
|
||||
: mRawPtr(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename I>
|
||||
MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr)
|
||||
: mRawPtr(aSmartPtr.take())
|
||||
|
@ -155,6 +160,13 @@ public:
|
|||
|
||||
// Assignment operators
|
||||
|
||||
RefPtr<T>&
|
||||
operator=(decltype(nullptr))
|
||||
{
|
||||
assign_assuming_AddRef(nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RefPtr<T>&
|
||||
operator=(const RefPtr<T>& aRhs)
|
||||
// copy assignment operator
|
||||
|
@ -243,7 +255,7 @@ public:
|
|||
// return the value of mRawPtr and null out mRawPtr. Useful for
|
||||
// already_AddRefed return values.
|
||||
{
|
||||
T* temp = 0;
|
||||
T* temp = nullptr;
|
||||
swap(temp);
|
||||
return already_AddRefed<T>(temp);
|
||||
}
|
||||
|
@ -258,7 +270,7 @@ public:
|
|||
{
|
||||
MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
|
||||
*aRhs = mRawPtr;
|
||||
mRawPtr = 0;
|
||||
mRawPtr = nullptr;
|
||||
}
|
||||
|
||||
T*
|
||||
|
@ -303,7 +315,7 @@ public:
|
|||
T*
|
||||
operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
|
||||
{
|
||||
MOZ_ASSERT(mRawPtr != 0,
|
||||
MOZ_ASSERT(mRawPtr != nullptr,
|
||||
"You can't dereference a NULL RefPtr with operator->().");
|
||||
return get();
|
||||
}
|
||||
|
@ -330,7 +342,7 @@ public:
|
|||
template <typename R, typename... Args>
|
||||
Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const
|
||||
{
|
||||
MOZ_ASSERT(mRawPtr != 0,
|
||||
MOZ_ASSERT(mRawPtr != nullptr,
|
||||
"You can't dereference a NULL RefPtr with operator->*().");
|
||||
return Proxy<R, Args...>(get(), aFptr);
|
||||
}
|
||||
|
@ -355,7 +367,7 @@ public:
|
|||
T&
|
||||
operator*() const
|
||||
{
|
||||
MOZ_ASSERT(mRawPtr != 0,
|
||||
MOZ_ASSERT(mRawPtr != nullptr,
|
||||
"You can't dereference a NULL RefPtr with operator*().");
|
||||
return *get();
|
||||
}
|
||||
|
@ -363,7 +375,7 @@ public:
|
|||
T**
|
||||
StartAssignment()
|
||||
{
|
||||
assign_assuming_AddRef(0);
|
||||
assign_assuming_AddRef(nullptr);
|
||||
return reinterpret_cast<T**>(&mRawPtr);
|
||||
}
|
||||
private:
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.mozilla.gecko.util.NativeEventListener;
|
|||
import org.mozilla.gecko.util.NativeJSObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -88,7 +89,8 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
|||
"MediaPlayer:Mirror",
|
||||
"MediaPlayer:Message",
|
||||
"AndroidCastDevice:Start",
|
||||
"AndroidCastDevice:Stop");
|
||||
"AndroidCastDevice:Stop",
|
||||
"AndroidCastDevice:SyncDevice");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -105,7 +107,8 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
|||
"MediaPlayer:Mirror",
|
||||
"MediaPlayer:Message",
|
||||
"AndroidCastDevice:Start",
|
||||
"AndroidCastDevice:Stop");
|
||||
"AndroidCastDevice:Stop",
|
||||
"AndroidCastDevice:SyncDevice");
|
||||
}
|
||||
|
||||
// GeckoEventListener implementation
|
||||
|
@ -145,16 +148,29 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
|||
}
|
||||
|
||||
if (event.startsWith("AndroidCastDevice:")) {
|
||||
final GeckoPresentationDisplay display = displays.get(message.getString("id"));
|
||||
if (display == null) {
|
||||
Log.e(LOGTAG, "Couldn't find a display for this id: " + message.getString("id") + " for message: " + event);
|
||||
return;
|
||||
}
|
||||
|
||||
if ("AndroidCastDevice:Start".equals(event)) {
|
||||
final GeckoPresentationDisplay display = displays.get(message.getString("id"));
|
||||
if (display == null) {
|
||||
Log.e(LOGTAG, "Couldn't find a display for this id: " + message.getString("id") + " for message: " + event);
|
||||
return;
|
||||
}
|
||||
display.start(callback);
|
||||
} else if ("AndroidCastDevice:Stop".equals(event)) {
|
||||
final GeckoPresentationDisplay display = displays.get(message.getString("id"));
|
||||
if (display == null) {
|
||||
Log.e(LOGTAG, "Couldn't find a display for this id: " + message.getString("id") + " for message: " + event);
|
||||
return;
|
||||
}
|
||||
display.stop(callback);
|
||||
} else if ("AndroidCastDevice:SyncDevice".equals(event)) {
|
||||
for (Map.Entry<String, GeckoPresentationDisplay> entry : displays.entrySet()) {
|
||||
GeckoPresentationDisplay display = entry.getValue();
|
||||
JSONObject json = display.toJSON();
|
||||
if (json == null) {
|
||||
break;
|
||||
}
|
||||
GeckoAppShell.notifyObservers("AndroidCastDevice:Added", json.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* -*- Mode: 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/. */
|
||||
|
@ -5,6 +7,10 @@
|
|||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
const TOPIC_PRESENTATION_VIEW_READY = "presentation-view-ready";
|
||||
const TOPIC_PRESENTATION_RECEIVER_LAUNCH = "presentation-receiver:launch";
|
||||
const TOPIC_PRESENTATION_RECEIVER_LAUNCH_RESPONSE = "presentation-receiver:launch:response";
|
||||
|
||||
// globals Services
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
@ -18,5 +24,40 @@ let PresentationView = {
|
|||
startup: function startup() {
|
||||
// use hash as the ID of this top level window
|
||||
this._id = window.location.hash.substr(1);
|
||||
|
||||
// Listen "presentation-receiver:launch" sent from
|
||||
// PresentationRequestUIGlue.
|
||||
Services.obs.addObserver(this,TOPIC_PRESENTATION_RECEIVER_LAUNCH, false);
|
||||
|
||||
// Notify PresentationView is ready.
|
||||
Services.obs.notifyObservers(null, TOPIC_PRESENTATION_VIEW_READY, this._id);
|
||||
},
|
||||
|
||||
stop: function stop() {
|
||||
Services.obs.removeObserver(this, TOPIC_PRESENTATION_RECEIVER_LAUNCH);
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
log("Got observe: aTopic=" + aTopic);
|
||||
|
||||
let requestData = JSON.parse(aData);
|
||||
if (this._id != requestData.windowId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let browser = document.getElementById("content");
|
||||
browser.setAttribute("mozpresentation", requestData.url);
|
||||
try {
|
||||
browser.loadURI(requestData.url);
|
||||
Services.obs.notifyObservers(browser,
|
||||
TOPIC_PRESENTATION_RECEIVER_LAUNCH_RESPONSE,
|
||||
JSON.stringify({ result: "success",
|
||||
requestId: requestData.requestId }));
|
||||
} catch (e) {
|
||||
Services.obs.notifyObservers(null,
|
||||
TOPIC_PRESENTATION_RECEIVER_LAUNCH_RESPONSE,
|
||||
JSON.stringify({ result: "error",
|
||||
reason: e.message }));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
<window id="presentation-window"
|
||||
onload="PresentationView.startup();"
|
||||
onunload="PresentationView.stop();"
|
||||
windowtype="navigator:browser"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
|
|
|
@ -46,6 +46,10 @@ contract @mozilla.org/network/authprompt-adapter-factory;1 {80dae1e9-e0d2-4974-9
|
|||
component {388bd149-c919-4a43-b646-d7ec57877689} PresentationDevicePrompt.js
|
||||
contract @mozilla.org/presentation-device/prompt;1 {388bd149-c919-4a43-b646-d7ec57877689}
|
||||
|
||||
# PresentationRequestUIGlue.js
|
||||
component {9c550ef7-3ff6-4bd1-9ad1-5a3735b90d21} PresentationRequestUIGlue.js
|
||||
contract @mozilla.org/presentation/requestuiglue;1 {9c550ef7-3ff6-4bd1-9ad1-5a3735b90d21}
|
||||
|
||||
# ImageBlockingPolicy.js
|
||||
component {f55f77f9-d33d-4759-82fc-60db3ee0bb91} ImageBlockingPolicy.js
|
||||
contract @mozilla.org/browser/blockimages-policy;1 {f55f77f9-d33d-4759-82fc-60db3ee0bb91}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/* -*- Mode: 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/. */
|
||||
|
||||
"use strict"
|
||||
|
||||
const { interfaces: Ci, utils: Cu, classes: Cc } = Components;
|
||||
|
||||
const TOPIC_PRESENTATION_RECEIVER_LAUNCH = "presentation-receiver:launch";
|
||||
const TOPIC_PRESENTATION_RECEIVER_LAUNCH_RESPONSE = "presentation-receiver:launch:response";
|
||||
|
||||
// globals XPCOMUtils
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
// globals Services
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function log(str) {
|
||||
// dump("-*- PresentationRequestUIGlue.js -*-: " + str + "\n");
|
||||
}
|
||||
|
||||
function PresentationRequestUIGlue() { }
|
||||
|
||||
PresentationRequestUIGlue.prototype = {
|
||||
sendRequest: function sendRequest(aURL, aSessionId, aDevice) {
|
||||
log("PresentationRequestUIGlue - sendRequest aURL=" + aURL +
|
||||
" aSessionId=" + aSessionId);
|
||||
|
||||
let localDevice;
|
||||
try {
|
||||
localDevice = aDevice.QueryInterface(Ci.nsIPresentationLocalDevice);
|
||||
} catch (e) {
|
||||
/* XXX: Currently, Fennec only support 1-UA devices. Remove this
|
||||
* Promise.reject() when it starts to support 2-UA devices.
|
||||
*/
|
||||
log("Not an 1-UA device.")
|
||||
return new Promise.reject();
|
||||
}
|
||||
|
||||
return new Promise((aResolve, aReject) => {
|
||||
|
||||
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator);
|
||||
let requestId = uuidGenerator.generateUUID().toString();
|
||||
|
||||
let handleObserve = (aSubject, aTopic, aData) => {
|
||||
log("Got observe: aTopic=" + aTopic);
|
||||
|
||||
let data = JSON.parse(aData);
|
||||
if (data.requestId != requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(handleObserve,
|
||||
TOPIC_PRESENTATION_RECEIVER_LAUNCH_RESPONSE);
|
||||
switch(data.result) {
|
||||
case "success":
|
||||
aResolve(aSubject);
|
||||
break;
|
||||
case "error":
|
||||
aReject();
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
Services.obs.addObserver(handleObserve,
|
||||
TOPIC_PRESENTATION_RECEIVER_LAUNCH_RESPONSE,
|
||||
false);
|
||||
|
||||
let data = {
|
||||
url: aURL,
|
||||
windowId: localDevice.windowId,
|
||||
requestId: requestId
|
||||
};
|
||||
Services.obs.notifyObservers(null,
|
||||
TOPIC_PRESENTATION_RECEIVER_LAUNCH,
|
||||
JSON.stringify(data));
|
||||
})
|
||||
},
|
||||
|
||||
classID: Components.ID("9c550ef7-3ff6-4bd1-9ad1-5a3735b90d21"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationRequestUIGlue])
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationRequestUIGlue]);
|
|
@ -27,6 +27,7 @@ EXTRA_COMPONENTS += [
|
|||
'NSSDialogService.js',
|
||||
'PersistentNotificationHandler.js',
|
||||
'PresentationDevicePrompt.js',
|
||||
'PresentationRequestUIGlue.js',
|
||||
'PromptService.js',
|
||||
'SessionStore.js',
|
||||
'SiteSpecificUserAgent.js',
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
; 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/.
|
||||
|
@ -405,6 +404,8 @@
|
|||
@BINPATH@/components/PresentationDataChannelSessionTransport.manifest
|
||||
@BINPATH@/components/LegacyProviders.manifest
|
||||
@BINPATH@/components/LegacyPresentationControlService.js
|
||||
@BINPATH@/components/AndroidCastDeviceProvider.manifest
|
||||
@BINPATH@/components/AndroidCastDeviceProvider.js
|
||||
|
||||
@BINPATH@/components/TVSimulatorService.js
|
||||
@BINPATH@/components/TVSimulatorService.manifest
|
||||
|
@ -531,6 +532,7 @@
|
|||
@BINPATH@/components/NSSDialogService.js
|
||||
@BINPATH@/components/PersistentNotificationHandler.js
|
||||
@BINPATH@/components/PresentationDevicePrompt.js
|
||||
@BINPATH@/components/PresentationRequestUIGlue.js
|
||||
@BINPATH@/components/PromptService.js
|
||||
@BINPATH@/components/SessionStore.js
|
||||
@BINPATH@/components/SiteSpecificUserAgent.js
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче