зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
This commit is contained in:
Коммит
8ed4c0a1dd
|
@ -37,6 +37,8 @@
|
|||
iframe.src = `data:text/html,<html><body>hey</body></html>`;
|
||||
iframe.onload = () => resolve(iframe.contentDocument);
|
||||
document.body.appendChild(iframe);
|
||||
document.body.offsetTop; // We rely on the a11y tree being created
|
||||
// already, and it's created off layout.
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -118,7 +120,7 @@
|
|||
];
|
||||
break;
|
||||
default:
|
||||
ok(false, "Unexpected amount of states");
|
||||
ok(false, "Unexpected amount of states: " + JSON.stringify(anode.states));
|
||||
}
|
||||
if (states) {
|
||||
for (let i = 0; i < states.length; i++) {
|
||||
|
|
|
@ -18,10 +18,11 @@
|
|||
"chrome_settings_overrides": {
|
||||
"search_provider": {
|
||||
"name": "Prisjakt",
|
||||
"search_url": "https://www.prisjakt.nu/#rparams=ss={searchTerms}",
|
||||
"search_form": "https://www.prisjakt.nu/#rparams=ss={searchTerms}",
|
||||
"search_url": "https://www.prisjakt.nu/search",
|
||||
"search_url_get_params": "search={searchTerms}",
|
||||
"search_form": "https://www.prisjakt.nu/search?search={searchTerms}",
|
||||
"suggest_url": "https://www.prisjakt.nu/plugins/opensearch/suggestions.php",
|
||||
"suggest_url_get_params": "search={searchTerms}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,10 +56,12 @@ class AccessibilityStartup {
|
|||
this._supports.relations,
|
||||
this._supports.snapshot,
|
||||
this._supports.audit,
|
||||
this._supports.hydration,
|
||||
] = await Promise.all([
|
||||
this.target.actorHasMethod("accessible", "getRelations"),
|
||||
this.target.actorHasMethod("accessible", "snapshot"),
|
||||
this.target.actorHasMethod("accessible", "audit"),
|
||||
this.target.actorHasMethod("accessible", "hydrate"),
|
||||
]));
|
||||
|
||||
await this._accessibility.bootstrap();
|
||||
|
|
|
@ -79,8 +79,12 @@ AccessibilityView.prototype = {
|
|||
window.emit(EVENTS.NEW_ACCESSIBLE_FRONT_HIGHLIGHTED);
|
||||
},
|
||||
|
||||
async selectNodeAccessible(walker, node) {
|
||||
async selectNodeAccessible(walker, node, supports) {
|
||||
let accessible = await walker.getAccessibleFor(node);
|
||||
if (accessible && supports.hydration) {
|
||||
await accessible.hydrate();
|
||||
}
|
||||
|
||||
// If node does not have an accessible object, try to find node's child text node and
|
||||
// try to retrieve an accessible object for that child instead. This is the best
|
||||
// effort approach until there's accessibility API to retrieve accessible object at
|
||||
|
@ -90,7 +94,13 @@ AccessibilityView.prototype = {
|
|||
for (const child of children) {
|
||||
if (child.nodeType === nodeConstants.TEXT_NODE) {
|
||||
accessible = await walker.getAccessibleFor(child);
|
||||
if (accessible && accessible.indexInParent >= 0) {
|
||||
// indexInParent property is only available with additional request
|
||||
// for data (hydration) about the accessible object.
|
||||
if (accessible && supports.hydration) {
|
||||
await accessible.hydrate();
|
||||
}
|
||||
|
||||
if (accessible.indexInParent >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,5 +17,6 @@ exports.updateDetails = (domWalker, accessible, supports) =>
|
|||
domWalker.getNodeFromActor(accessible.actorID, ["rawAccessible", "DOMNode"]),
|
||||
supports.relations ? accessible.getRelations() : [],
|
||||
supports.audit ? accessible.audit() : {},
|
||||
supports.hydration ? accessible.hydrate() : null,
|
||||
]).then(response => dispatch({ accessible, type: UPDATE_DETAILS, response }))
|
||||
.catch(error => dispatch({ accessible, type: UPDATE_DETAILS, error }));
|
||||
|
|
|
@ -8,19 +8,12 @@ const React = require("devtools/client/shared/vendor/react");
|
|||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
|
||||
const { getContrastRatioScore } = require("./ColorContrastAccessibility");
|
||||
const { isFiltered } = require("../utils/audit");
|
||||
const { FILTERS } = require("../constants");
|
||||
const { accessibility: { AUDIT_TYPE, ColorContrastScores } } =
|
||||
require("devtools/shared/constants");
|
||||
const { accessibility: { AUDIT_TYPE, SCORES } } = require("devtools/shared/constants");
|
||||
|
||||
function validateContrast({ error, value, min, isLargeText }) {
|
||||
if (error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const score = getContrastRatioScore(value || min, isLargeText);
|
||||
return score === ColorContrastScores.FAIL;
|
||||
function validateContrast({ error, score }) {
|
||||
return !error && score === SCORES.FAIL;
|
||||
}
|
||||
|
||||
const AUDIT_TYPE_TO_FILTER = {
|
||||
|
|
|
@ -11,7 +11,6 @@ const LearnMoreLink = createFactory(require("./LearnMoreLink"));
|
|||
|
||||
const { A11Y_CONTRAST_LEARN_MORE_LINK } = require("../constants");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const { accessibility: { ColorContrastScores } } = require("devtools/shared/constants");
|
||||
|
||||
/**
|
||||
* Component that renders a colour contrast value along with a swatch preview of what the
|
||||
|
@ -22,8 +21,8 @@ class ContrastValueClass extends Component {
|
|||
return {
|
||||
backgroundColor: PropTypes.array.isRequired,
|
||||
color: PropTypes.array.isRequired,
|
||||
isLargeText: PropTypes.bool.isRequired,
|
||||
value: PropTypes.number.isRequired,
|
||||
score: PropTypes.string,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -31,13 +30,13 @@ class ContrastValueClass extends Component {
|
|||
const {
|
||||
backgroundColor,
|
||||
color,
|
||||
isLargeText,
|
||||
value,
|
||||
score,
|
||||
} = this.props;
|
||||
|
||||
const className = [
|
||||
"accessibility-contrast-value",
|
||||
getContrastRatioScore(value, isLargeText),
|
||||
score,
|
||||
].join(" ");
|
||||
|
||||
return (
|
||||
|
@ -71,6 +70,9 @@ class ColorContrastAccessibilityClass extends Component {
|
|||
backgroundColor: PropTypes.array,
|
||||
backgroundColorMin: PropTypes.array,
|
||||
backgroundColorMax: PropTypes.array,
|
||||
score: PropTypes.string,
|
||||
scoreMin: PropTypes.string,
|
||||
scoreMax: PropTypes.string,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -79,9 +81,9 @@ class ColorContrastAccessibilityClass extends Component {
|
|||
error,
|
||||
isLargeText,
|
||||
color,
|
||||
value, backgroundColor,
|
||||
min, backgroundColorMin,
|
||||
max, backgroundColorMax,
|
||||
value, backgroundColor, score,
|
||||
min, backgroundColorMin, scoreMin,
|
||||
max, backgroundColorMax, scoreMax,
|
||||
} = this.props;
|
||||
|
||||
const children = [];
|
||||
|
@ -99,17 +101,17 @@ class ColorContrastAccessibilityClass extends Component {
|
|||
}
|
||||
|
||||
if (value) {
|
||||
children.push(ContrastValue({ isLargeText, color, backgroundColor, value }));
|
||||
children.push(ContrastValue({ score, color, backgroundColor, value }));
|
||||
} else {
|
||||
children.push(
|
||||
ContrastValue(
|
||||
{ isLargeText, color, backgroundColor: backgroundColorMin, value: min }),
|
||||
{ score: scoreMin, color, backgroundColor: backgroundColorMin, value: min }),
|
||||
div({
|
||||
role: "presentation",
|
||||
className: "accessibility-color-contrast-separator",
|
||||
}),
|
||||
ContrastValue(
|
||||
{ isLargeText, color, backgroundColor: backgroundColorMax, value: max }),
|
||||
{ score: scoreMax, color, backgroundColor: backgroundColorMax, value: max }),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -140,15 +142,12 @@ const ColorContrastAccessibility = createFactory(ColorContrastAccessibilityClass
|
|||
class ContrastAnnotationClass extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
isLargeText: PropTypes.bool.isRequired,
|
||||
value: PropTypes.number,
|
||||
min: PropTypes.number,
|
||||
score: PropTypes.string,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isLargeText, min, value } = this.props;
|
||||
const score = getContrastRatioScore(value || min, isLargeText);
|
||||
const { score } = this.props;
|
||||
|
||||
return (
|
||||
LearnMoreLink(
|
||||
|
@ -191,31 +190,7 @@ class ColorContrastCheck extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contrast ratio score.
|
||||
* ratio.
|
||||
* @param {Number} value
|
||||
* Value of the contrast ratio for a given accessible object.
|
||||
* @param {Boolean} isLargeText
|
||||
* True if the accessible object contains large text.
|
||||
* @return {String}
|
||||
* Represents the appropriate contrast ratio score.
|
||||
*/
|
||||
function getContrastRatioScore(value, isLargeText) {
|
||||
const levels = isLargeText ? { AA: 3, AAA: 4.5 } : { AA: 4.5, AAA: 7 };
|
||||
|
||||
let score = ColorContrastScores.FAIL;
|
||||
if (value >= levels.AAA) {
|
||||
score = ColorContrastScores.AAA;
|
||||
} else if (value >= levels.AA) {
|
||||
score = ColorContrastScores.AA;
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ColorContrastAccessibility: ColorContrastAccessibilityClass,
|
||||
ColorContrastCheck,
|
||||
getContrastRatioScore,
|
||||
};
|
||||
|
|
|
@ -9,8 +9,7 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
|||
|
||||
const { L10N } = require("../utils/l10n");
|
||||
|
||||
const { getContrastRatioScore } = require("./ColorContrastAccessibility");
|
||||
const { accessibility: { ColorContrastScores } } = require("devtools/shared/constants");
|
||||
const { accessibility: { SCORES } } = require("devtools/shared/constants");
|
||||
|
||||
loader.lazyGetter(this, "Badge", () => createFactory(require("./Badge")));
|
||||
|
||||
|
@ -26,21 +25,18 @@ class ContrastBadge extends Component {
|
|||
static get propTypes() {
|
||||
return {
|
||||
error: PropTypes.string,
|
||||
isLargeText: PropTypes.bool.isRequired,
|
||||
value: PropTypes.number,
|
||||
min: PropTypes.number,
|
||||
score: PropTypes.string,
|
||||
walker: PropTypes.object.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { error, value, min, isLargeText, walker } = this.props;
|
||||
const { error, score, walker } = this.props;
|
||||
if (error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const score = getContrastRatioScore(value || min, isLargeText);
|
||||
if (score !== ColorContrastScores.FAIL) {
|
||||
if (score !== SCORES.FAIL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -154,7 +154,8 @@ AccessibilityPanel.prototype = {
|
|||
"devtools.accessibility.select_accessible_for_node", reason, 1);
|
||||
}
|
||||
|
||||
this.postContentMessage("selectNodeAccessible", this.walker, nodeFront);
|
||||
this.postContentMessage("selectNodeAccessible", this.walker, nodeFront,
|
||||
this.supports);
|
||||
},
|
||||
|
||||
highlightAccessible(accessibleFront) {
|
||||
|
|
|
@ -43,6 +43,7 @@ const tests = [{
|
|||
"color": [255, 0, 0, 1],
|
||||
"backgroundColor": [255, 255, 255, 1],
|
||||
"isLargeText": false,
|
||||
"score": "fail",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -59,6 +60,7 @@ const tests = [{
|
|||
"color": [0, 0, 255, 1],
|
||||
"backgroundColor": [255, 255, 255, 1],
|
||||
"isLargeText": false,
|
||||
"score": "AAA",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -62,6 +62,7 @@ describe("AuditController component:", () => {
|
|||
"color": [255, 0, 0, 1],
|
||||
"backgroundColor": [255, 255, 255, 1],
|
||||
"isLargeText": false,
|
||||
"score": "AA",
|
||||
},
|
||||
},
|
||||
}, span())));
|
||||
|
@ -79,6 +80,7 @@ describe("AuditController component:", () => {
|
|||
"color": [255, 0, 0, 1],
|
||||
"backgroundColor": [255, 255, 255, 1],
|
||||
"isLargeText": false,
|
||||
"score": "fail",
|
||||
};
|
||||
|
||||
const wrapper = mount(Provider({store}, AuditFilter({
|
||||
|
@ -102,6 +104,7 @@ describe("AuditController component:", () => {
|
|||
"backgroundColorMin": [219, 106, 116, 1],
|
||||
"backgroundColorMax": [156, 145, 211, 1],
|
||||
"isLargeText": false,
|
||||
"score": "fail",
|
||||
};
|
||||
|
||||
const wrapper = mount(Provider({store}, AuditFilter({
|
||||
|
|
|
@ -51,6 +51,7 @@ describe("Badges component:", () => {
|
|||
"color": [255, 0, 0, 1],
|
||||
"backgroundColor": [255, 255, 255, 1],
|
||||
"isLargeText": false,
|
||||
"score": "AA",
|
||||
},
|
||||
},
|
||||
})));
|
||||
|
@ -64,6 +65,7 @@ describe("Badges component:", () => {
|
|||
"color": [255, 0, 0, 1],
|
||||
"backgroundColor": [255, 255, 255, 1],
|
||||
"isLargeText": false,
|
||||
"score": "fail",
|
||||
};
|
||||
const wrapper = mount(Provider({ store }, Badges({ checks: { CONTRAST }})));
|
||||
|
||||
|
@ -81,6 +83,7 @@ describe("Badges component:", () => {
|
|||
"backgroundColorMin": [219, 106, 116, 1],
|
||||
"backgroundColorMax": [156, 145, 211, 1],
|
||||
"isLargeText": false,
|
||||
"score": "fail",
|
||||
};
|
||||
const wrapper = mount(Provider({ store }, Badges({ checks: { CONTRAST }})));
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ describe("ContrastBadge component:", () => {
|
|||
const wrapper = shallow(ContrastBadge({
|
||||
value: 5.11,
|
||||
isLargeText: false,
|
||||
score: "AA",
|
||||
}));
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
expect(wrapper.isEmptyRender()).toBe(true);
|
||||
|
@ -39,6 +40,7 @@ describe("ContrastBadge component:", () => {
|
|||
min: 5.11,
|
||||
max: 6.25,
|
||||
isLargeText: false,
|
||||
score: "AA",
|
||||
}));
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
expect(wrapper.isEmptyRender()).toBe(true);
|
||||
|
@ -48,6 +50,7 @@ describe("ContrastBadge component:", () => {
|
|||
const wrapper = shallow(ContrastBadge({
|
||||
value: 3.77,
|
||||
isLargeText: true,
|
||||
score: "AA",
|
||||
}));
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
expect(wrapper.isEmptyRender()).toBe(true);
|
||||
|
@ -57,6 +60,7 @@ describe("ContrastBadge component:", () => {
|
|||
const wrapper = mount(Provider({ store }, ContrastBadge({
|
||||
value: 3.77,
|
||||
isLargeText: false,
|
||||
score: "fail",
|
||||
})));
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
|
|
|
@ -41,6 +41,7 @@ window.onload = async function() {
|
|||
"color": [255, 0, 0, 1],
|
||||
"backgroundColor": [255, 255, 255, 1],
|
||||
"isLargeText": false,
|
||||
"score": "fail",
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -52,6 +53,9 @@ window.onload = async function() {
|
|||
"backgroundColorMin": [219, 106, 116, 1],
|
||||
"backgroundColorMax": [156, 145, 211, 1],
|
||||
"isLargeText": false,
|
||||
"score": "fail",
|
||||
"scoreMin": "fail",
|
||||
"scoreMax": "fail",
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -61,6 +65,7 @@ window.onload = async function() {
|
|||
"color": [255, 0, 0, 1],
|
||||
"backgroundColor": [255, 255, 255, 1],
|
||||
"isLargeText": true,
|
||||
"score": "AA",
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
|
|
|
@ -150,7 +150,7 @@ async function testClickInInnerIframe(doc) {
|
|||
const onFrameLoad = new Promise(r => {
|
||||
iframe.addEventListener("load", r, true);
|
||||
});
|
||||
iframe.src = "data:text/html,<div id=test style='height:50px;'></div>";
|
||||
iframe.srcdoc = "<div id=test style='height:50px;'></div>";
|
||||
await onFrameLoad;
|
||||
|
||||
tooltip.setContentSize({width: 100, height: 50});
|
||||
|
|
|
@ -366,16 +366,29 @@ const AccessibleActor = ActorClassWithSpec(accessibleSpec, {
|
|||
actor: this.actorID,
|
||||
role: this.role,
|
||||
name: this.name,
|
||||
childCount: this.childCount,
|
||||
checks: this._lastAudit,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Provide additional (full) information about the accessible object that is
|
||||
* otherwise missing from the form.
|
||||
*
|
||||
* @return {Object}
|
||||
* Object that contains accessible object information such as states,
|
||||
* actions, attributes, etc.
|
||||
*/
|
||||
hydrate() {
|
||||
return {
|
||||
value: this.value,
|
||||
description: this.description,
|
||||
keyboardShortcut: this.keyboardShortcut,
|
||||
childCount: this.childCount,
|
||||
domNodeType: this.domNodeType,
|
||||
indexInParent: this.indexInParent,
|
||||
states: this.states,
|
||||
actions: this.actions,
|
||||
attributes: this.attributes,
|
||||
checks: this._lastAudit,
|
||||
};
|
||||
},
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ loader.lazyRequireGetter(this, "getCurrentZoom", "devtools/shared/layout/utils",
|
|||
loader.lazyRequireGetter(this, "addPseudoClassLock", "devtools/server/actors/highlighters/utils/markup", true);
|
||||
loader.lazyRequireGetter(this, "removePseudoClassLock", "devtools/server/actors/highlighters/utils/markup", true);
|
||||
loader.lazyRequireGetter(this, "DevToolsWorker", "devtools/shared/worker/worker", true);
|
||||
loader.lazyRequireGetter(this, "accessibility", "devtools/shared/constants", true);
|
||||
|
||||
const WORKER_URL = "resource://devtools/server/actors/accessibility/worker.js";
|
||||
const HIGHLIGHTED_PSEUDO_CLASS = ":-moz-devtools-highlighted";
|
||||
|
@ -109,6 +110,29 @@ function getImageCtx(win, bounds, zoom, scale, node) {
|
|||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contrast ratio score based on WCAG criteria.
|
||||
* @param {Number} ratio
|
||||
* Value of the contrast ratio for a given accessible object.
|
||||
* @param {Boolean} isLargeText
|
||||
* True if the accessible object contains large text.
|
||||
* @return {String}
|
||||
* Value that represents calculated contrast ratio score.
|
||||
*/
|
||||
function getContrastRatioScore(ratio, isLargeText) {
|
||||
const { SCORES: { FAIL, AA, AAA } } = accessibility;
|
||||
const levels = isLargeText ? { AA: 3, AAA: 4.5 } : { AA: 4.5, AAA: 7 };
|
||||
|
||||
let score = FAIL;
|
||||
if (ratio >= levels.AAA) {
|
||||
score = AAA;
|
||||
} else if (ratio >= levels.AA) {
|
||||
score = AA;
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the contrast ratio of the referenced DOM node.
|
||||
*
|
||||
|
@ -177,11 +201,13 @@ async function getContrastRatioFor(node, options = {}) {
|
|||
}
|
||||
|
||||
if (rgba.value) {
|
||||
const value = colorUtils.calculateContrastRatio(rgba.value, color);
|
||||
return {
|
||||
value: colorUtils.calculateContrastRatio(rgba.value, color),
|
||||
value,
|
||||
color,
|
||||
backgroundColor: rgba.value,
|
||||
isLargeText,
|
||||
score: getContrastRatioScore(value, isLargeText),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -194,6 +220,8 @@ async function getContrastRatioFor(node, options = {}) {
|
|||
[rgba.min, rgba.max] = [rgba.max, rgba.min];
|
||||
}
|
||||
|
||||
const score = getContrastRatioScore(min, isLargeText);
|
||||
|
||||
return {
|
||||
min,
|
||||
max,
|
||||
|
@ -201,6 +229,9 @@ async function getContrastRatioFor(node, options = {}) {
|
|||
backgroundColorMin: rgba.min,
|
||||
backgroundColorMax: rgba.max,
|
||||
isLargeText,
|
||||
score,
|
||||
scoreMin: score,
|
||||
scoreMax: getContrastRatioScore(max, isLargeText),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ loader.lazyRequireGetter(this, "isXUL", "devtools/server/actors/highlighters/uti
|
|||
loader.lazyRequireGetter(this, "loadSheet", "devtools/shared/layout/utils", true);
|
||||
loader.lazyRequireGetter(this, "register", "devtools/server/actors/highlighters", true);
|
||||
loader.lazyRequireGetter(this, "removeSheet", "devtools/shared/layout/utils", true);
|
||||
loader.lazyRequireGetter(this, "accessibility", "devtools/shared/constants", true);
|
||||
|
||||
const kStateHover = 0x00000004; // NS_EVENT_STATE_HOVER
|
||||
|
||||
|
@ -405,7 +406,10 @@ const AccessibleWalkerActor = ActorClassWithSpec(accessibleWalkerSpec, {
|
|||
|
||||
const ancestries = [];
|
||||
for (const [acc, audit] of report.entries()) {
|
||||
if (audit && Object.values(audit).filter(check => check != null).length > 0) {
|
||||
// Filter out audits that have no failing checks.
|
||||
if (audit &&
|
||||
Object.values(audit).some(check => check != null && !check.error &&
|
||||
check.score === accessibility.SCORES.FAIL)) {
|
||||
ancestries.push(this.getAncestry(acc));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ const { getCurrentZoom, getViewportDimensions } = require("devtools/shared/layou
|
|||
const { moveInfobar, createNode } = require("./markup");
|
||||
const { truncateString } = require("devtools/shared/inspector/utils");
|
||||
|
||||
const { accessibility: { ColorContrastScores } } = require("devtools/shared/constants");
|
||||
const { accessibility: { SCORES } } = require("devtools/shared/constants");
|
||||
|
||||
const STRINGS_URI = "devtools/shared/locales/accessibility.properties";
|
||||
loader.lazyRequireGetter(this, "LocalizationHelper", "devtools/shared/l10n", true);
|
||||
|
@ -527,11 +527,10 @@ class ContrastRatio extends AuditReport {
|
|||
});
|
||||
}
|
||||
|
||||
_fillAndStyleContrastValue(el, { value, isLargeText, color, backgroundColor }) {
|
||||
_fillAndStyleContrastValue(el, { value, className, color, backgroundColor }) {
|
||||
value = value.toFixed(2);
|
||||
const style = getContrastRatioScoreStyle(value, isLargeText);
|
||||
this.setTextContent(el, value);
|
||||
el.classList.add(style);
|
||||
el.classList.add(className);
|
||||
el.setAttribute("style",
|
||||
`--accessibility-highlighter-contrast-ratio-color: rgba(${color});` +
|
||||
`--accessibility-highlighter-contrast-ratio-bg: rgba(${backgroundColor});`);
|
||||
|
@ -551,7 +550,7 @@ class ContrastRatio extends AuditReport {
|
|||
for (const key of ["label", "min", "max", "error", "separator"]) {
|
||||
const el = els[key] = this.getElement(`contrast-ratio-${key}`);
|
||||
if (["min", "max"].includes(key)) {
|
||||
Object.values(ColorContrastScores).forEach(
|
||||
Object.values(SCORES).forEach(
|
||||
className => el.classList.remove(className));
|
||||
this.setTextContent(el, "");
|
||||
}
|
||||
|
@ -574,18 +573,20 @@ class ContrastRatio extends AuditReport {
|
|||
}
|
||||
|
||||
if (contrastRatio.value) {
|
||||
const { value, color, backgroundColor } = contrastRatio;
|
||||
const { value, color, score, backgroundColor } = contrastRatio;
|
||||
this._fillAndStyleContrastValue(els.min,
|
||||
{ value, isLargeText, color, backgroundColor });
|
||||
{ value, className: score, color, backgroundColor });
|
||||
return true;
|
||||
}
|
||||
|
||||
const { min, max, color, backgroundColorMin, backgroundColorMax } = contrastRatio;
|
||||
const {
|
||||
min, max, color, backgroundColorMin, backgroundColorMax, scoreMin, scoreMax,
|
||||
} = contrastRatio;
|
||||
this._fillAndStyleContrastValue(els.min,
|
||||
{ value: min, isLargeText, color, backgroundColor: backgroundColorMin });
|
||||
{ value: min, className: scoreMin, color, backgroundColor: backgroundColorMin });
|
||||
els.separator.removeAttribute("hidden");
|
||||
this._fillAndStyleContrastValue(els.max,
|
||||
{ value: max, isLargeText, color, backgroundColor: backgroundColorMax });
|
||||
{ value: max, className: scoreMax, color, backgroundColor: backgroundColorMax });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -646,29 +647,6 @@ function getBounds(win, { x, y, w, h, zoom }) {
|
|||
return { left, right, top, bottom, width, height };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contrast ratio score styling to be applied on the element that renders the contrast
|
||||
* ratio.
|
||||
* @param {Number} ratio
|
||||
* Value of the contrast ratio for a given accessible object.
|
||||
* @param {Boolean} isLargeText
|
||||
* True if the accessible object contains large text.
|
||||
* @return {String}
|
||||
* CSS class that represents the appropriate contrast ratio score styling.
|
||||
*/
|
||||
function getContrastRatioScoreStyle(ratio, isLargeText) {
|
||||
const levels = isLargeText ? { AA: 3, AAA: 4.5 } : { AA: 4.5, AAA: 7 };
|
||||
|
||||
let style = ColorContrastScores.FAIL;
|
||||
if (ratio >= levels.AAA) {
|
||||
style = ColorContrastScores.AAA;
|
||||
} else if (ratio >= levels.AA) {
|
||||
style = ColorContrastScores.AA;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
exports.MAX_STRING_LENGTH = MAX_STRING_LENGTH;
|
||||
exports.getBounds = getBounds;
|
||||
exports.Infobar = Infobar;
|
||||
|
|
|
@ -16,6 +16,14 @@ add_task(async function() {
|
|||
const buttonNode = await walker.querySelector(walker.rootNode, "#button");
|
||||
const accessibleFront = await a11yWalker.getAccessibleFor(buttonNode);
|
||||
|
||||
checkA11yFront(accessibleFront, {
|
||||
name: "Accessible Button",
|
||||
role: "pushbutton",
|
||||
childCount: 1,
|
||||
});
|
||||
|
||||
await accessibleFront.hydrate();
|
||||
|
||||
checkA11yFront(accessibleFront, {
|
||||
name: "Accessible Button",
|
||||
role: "pushbutton",
|
||||
|
|
|
@ -37,6 +37,7 @@ add_task(async function() {
|
|||
"color": [0, 0, 0, 1],
|
||||
"backgroundColor": [255, 255, 255, 1],
|
||||
"isLargeText": true,
|
||||
score: "AAA",
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -21,6 +21,14 @@ add_task(async function() {
|
|||
const accessibleSliderFront = await a11yWalker.getAccessibleFor(sliderNode);
|
||||
const browser = gBrowser.selectedBrowser;
|
||||
|
||||
checkA11yFront(accessibleFront, {
|
||||
name: "Accessible Button",
|
||||
role: "pushbutton",
|
||||
childCount: 1,
|
||||
});
|
||||
|
||||
await accessibleFront.hydrate();
|
||||
|
||||
checkA11yFront(accessibleFront, {
|
||||
name: "Accessible Button",
|
||||
role: "pushbutton",
|
||||
|
@ -92,6 +100,7 @@ add_task(async function() {
|
|||
content.document.getElementById("button").setAttribute("aria-live", "polite")));
|
||||
|
||||
info("Value change event");
|
||||
await accessibleSliderFront.hydrate();
|
||||
checkA11yFront(accessibleSliderFront, { value: "5" });
|
||||
await emitA11yEvent(accessibleSliderFront, "value-change",
|
||||
() => checkA11yFront(accessibleSliderFront, { value: "6" }),
|
||||
|
@ -101,6 +110,7 @@ add_task(async function() {
|
|||
info("Reorder event");
|
||||
is(accessibleSliderFront.childCount, 1, "Slider has only 1 child");
|
||||
const [firstChild ] = await accessibleSliderFront.children();
|
||||
await firstChild.hydrate();
|
||||
is(firstChild.indexInParent, 0, "Slider's first child has correct index in parent");
|
||||
await emitA11yEvent(accessibleSliderFront, "reorder",
|
||||
childCount => {
|
||||
|
|
|
@ -12,27 +12,7 @@ add_task(async function() {
|
|||
const accessibles = [{
|
||||
name: "",
|
||||
role: "document",
|
||||
value: "",
|
||||
description: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 2,
|
||||
domNodeType: 9,
|
||||
indexInParent: 0,
|
||||
states: [
|
||||
"focused", "readonly", "focusable", "active", "opaque", "enabled", "sensitive",
|
||||
],
|
||||
actions: [],
|
||||
attributes: {
|
||||
display: "block",
|
||||
"explicit-name": "true",
|
||||
"margin-bottom": "8px",
|
||||
"margin-left": "8px",
|
||||
"margin-right": "8px",
|
||||
"margin-top": "8px",
|
||||
tag: "body",
|
||||
"text-align": "start",
|
||||
"text-indent": "0px",
|
||||
},
|
||||
checks: {
|
||||
"CONTRAST": null,
|
||||
},
|
||||
|
@ -40,27 +20,7 @@ add_task(async function() {
|
|||
name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " +
|
||||
"eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
role: "heading",
|
||||
value: "",
|
||||
description: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 1,
|
||||
domNodeType: 1,
|
||||
indexInParent: 0,
|
||||
states: [ "selectable text", "opaque", "enabled", "sensitive" ],
|
||||
actions: [],
|
||||
attributes: {
|
||||
display: "block",
|
||||
formatting: "block",
|
||||
id: "h1",
|
||||
level: "1",
|
||||
"margin-bottom": "21.4333px",
|
||||
"margin-left": "0px",
|
||||
"margin-right": "0px",
|
||||
"margin-top": "21.4333px",
|
||||
tag: "h1",
|
||||
"text-align": "start",
|
||||
"text-indent": "0px",
|
||||
},
|
||||
checks: {
|
||||
"CONTRAST": null,
|
||||
},
|
||||
|
@ -68,15 +28,7 @@ add_task(async function() {
|
|||
name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " +
|
||||
"eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
role: "text leaf",
|
||||
value: "",
|
||||
description: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 0,
|
||||
domNodeType: 3,
|
||||
indexInParent: 0,
|
||||
states: [ "opaque", "enabled", "sensitive" ],
|
||||
actions: [],
|
||||
attributes: { "explicit-name": "true" },
|
||||
checks: {
|
||||
"CONTRAST": {
|
||||
"value": 21,
|
||||
|
@ -88,41 +40,14 @@ add_task(async function() {
|
|||
}, {
|
||||
name: "",
|
||||
role: "paragraph",
|
||||
value: "",
|
||||
description: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 1,
|
||||
domNodeType: 1,
|
||||
indexInParent: 1,
|
||||
states: [ "selectable text", "opaque", "enabled", "sensitive" ],
|
||||
actions: [ "Press" ],
|
||||
attributes: {
|
||||
display: "block",
|
||||
formatting: "block",
|
||||
id: "p",
|
||||
"margin-bottom": "16px",
|
||||
"margin-left": "0px",
|
||||
"margin-right": "0px",
|
||||
"margin-top": "16px",
|
||||
tag: "p",
|
||||
"text-align": "start",
|
||||
"text-indent": "0px",
|
||||
},
|
||||
checks: {
|
||||
"CONTRAST": null,
|
||||
},
|
||||
}, {
|
||||
name: "Accessible Paragraph",
|
||||
role: "text leaf",
|
||||
value: "",
|
||||
description: "",
|
||||
keyboardShortcut: "",
|
||||
childCount: 0,
|
||||
domNodeType: 3,
|
||||
indexInParent: 0,
|
||||
states: [ "opaque", "enabled", "sensitive" ],
|
||||
actions: [],
|
||||
attributes: { "explicit-name": "true" },
|
||||
checks: {
|
||||
"CONTRAST": {
|
||||
"value": 21,
|
||||
|
|
|
@ -17,7 +17,7 @@ exports.accessibility = {
|
|||
},
|
||||
// Constants associated with WCAG guidelines score system:
|
||||
// failing -> AA -> AAA;
|
||||
ColorContrastScores: {
|
||||
SCORES: {
|
||||
FAIL: "fail",
|
||||
AA: "AA",
|
||||
AAA: "AAA",
|
||||
|
|
|
@ -85,7 +85,8 @@ class AccessibleFront extends FrontClassWithSpec(accessibleSpec) {
|
|||
|
||||
form(form) {
|
||||
this.actorID = form.actor;
|
||||
this._form = form;
|
||||
this._form = this._form || {};
|
||||
Object.assign(this._form, form);
|
||||
}
|
||||
|
||||
nameChange(name, parent, walker) {
|
||||
|
@ -145,6 +146,12 @@ class AccessibleFront extends FrontClassWithSpec(accessibleSpec) {
|
|||
audited(checks) {
|
||||
this._form.checks = checks;
|
||||
}
|
||||
|
||||
hydrate() {
|
||||
return super.hydrate().then(properties => {
|
||||
Object.assign(this._form, properties);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class AccessibleWalkerFront extends FrontClassWithSpec(accessibleWalkerSpec) {
|
||||
|
|
|
@ -102,6 +102,12 @@ const accessibleSpec = generateActorSpec({
|
|||
relations: RetVal("array:accessibleRelation"),
|
||||
},
|
||||
},
|
||||
hydrate: {
|
||||
request: {},
|
||||
response: {
|
||||
properties: RetVal("json"),
|
||||
},
|
||||
},
|
||||
snapshot: {
|
||||
request: {},
|
||||
response: {
|
||||
|
|
|
@ -117,6 +117,9 @@
|
|||
l3.detach();
|
||||
l4.detach();
|
||||
|
||||
// swapDocShells reflows asynchronously, ensure layout is
|
||||
// clean so that the viewport of f1 is the right size.
|
||||
$("f1").getBoundingClientRect();
|
||||
var s1_new = snapshotWindow($("f1").contentWindow);
|
||||
var [same, first, second] = compareSnapshots(s1_new, s2, true);
|
||||
ok(same, "Should reflow on swap. Expected " + second + " but got " + first);
|
||||
|
|
|
@ -7,14 +7,29 @@
|
|||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
</head>
|
||||
<script type="application/javascript">
|
||||
|
||||
function navigateAway() {
|
||||
// Anchor clicks are only handled if we have a pres-context, and we may not
|
||||
// have one yet by the time this runs, and getBoundingClientRect() won't
|
||||
// construct it after bug 1440537.
|
||||
//
|
||||
// So we may need to wait a few frames to make this reliable.
|
||||
//
|
||||
// FIXME(emilio, bug 1218456): This dance shouldn't be needed.
|
||||
let anchor = document.getElementById("anchor");
|
||||
if (anchor.getBoundingClientRect().width > 0)
|
||||
anchor.click();
|
||||
else
|
||||
requestAnimationFrame(navigateAway);
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
// this should fail the first time, but work the second
|
||||
try {
|
||||
// this should fail the first time, but work the second
|
||||
window.parent.ok_wrapper(true, "a document that was loaded, navigated to another document, had 'allow-same-origin' added and then was" +
|
||||
" navigated back should be same-origin with its parent");
|
||||
}
|
||||
catch (e) {
|
||||
sendMouseEvent({type:'click'}, 'anchor');
|
||||
} catch (e) {
|
||||
navigateAway();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
#include "mozilla/SVGContextPaint.h"
|
||||
#include "mozilla/TextUtils.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsFontMetrics.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsMathUtils.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsWhitespaceTokenizer.h"
|
||||
#include "SVGAnimationElement.h"
|
||||
#include "SVGAnimatedPreserveAspectRatio.h"
|
||||
|
@ -466,15 +468,37 @@ SVGViewportElement* SVGContentUtils::GetNearestViewportElement(
|
|||
|
||||
static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
|
||||
bool aHaveRecursed) {
|
||||
gfxMatrix matrix = aElement->PrependLocalTransformsTo(
|
||||
gfxMatrix(), aHaveRecursed ? eAllTransforms : eUserSpaceToParent);
|
||||
auto getLocalTransformHelper =
|
||||
[](SVGElement const* e, bool shouldIncludeChildToUserSpace) -> gfxMatrix {
|
||||
gfxMatrix ret;
|
||||
|
||||
if (auto* f = e->GetPrimaryFrame()) {
|
||||
ret = nsSVGUtils::GetTransformMatrixInUserSpace(f);
|
||||
} else {
|
||||
// FIXME: Ideally we should also return the correct matrix
|
||||
// for display:none, but currently transform related code relies
|
||||
// heavily on the present of a frame.
|
||||
// For now we just fall back to |PrependLocalTransformsTo| which
|
||||
// doesn't account for CSS transform.
|
||||
ret = e->PrependLocalTransformsTo({}, eUserSpaceToParent);
|
||||
}
|
||||
|
||||
if (shouldIncludeChildToUserSpace) {
|
||||
ret = e->PrependLocalTransformsTo({}, eChildToUserSpace) * ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
gfxMatrix matrix = getLocalTransformHelper(aElement, aHaveRecursed);
|
||||
|
||||
SVGElement* element = aElement;
|
||||
nsIContent* ancestor = aElement->GetFlattenedTreeParent();
|
||||
|
||||
while (ancestor && ancestor->IsSVGElement() &&
|
||||
!ancestor->IsSVGElement(nsGkAtoms::foreignObject)) {
|
||||
element = static_cast<SVGElement*>(ancestor);
|
||||
matrix *= element->PrependLocalTransformsTo(gfxMatrix()); // i.e. *A*ppend
|
||||
matrix *= getLocalTransformHelper(element, true);
|
||||
if (!aScreenCTM && SVGContentUtils::EstablishesViewport(element)) {
|
||||
if (!element->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG) &&
|
||||
!element->NodeInfo()->Equals(nsGkAtoms::symbol, kNameSpaceID_SVG)) {
|
||||
|
@ -501,7 +525,7 @@ static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
|
|||
// transforms in this case since that's what we've been doing for
|
||||
// a while, and it keeps us consistent with WebKit and Opera (if not
|
||||
// really with the ambiguous spec).
|
||||
matrix = aElement->PrependLocalTransformsTo(gfxMatrix());
|
||||
matrix = getLocalTransformHelper(aElement, true);
|
||||
}
|
||||
|
||||
if (auto* f = element->GetPrimaryFrame()) {
|
||||
|
|
|
@ -9,6 +9,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=366697
|
|||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<style>
|
||||
#padsvg1 { padding-left: 27px; padding-top: 43px; }
|
||||
#transrect1 { transform: scale(2,3); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -19,7 +20,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=366697
|
|||
<iframe id="svg" src="getCTM-helper.svg"></iframe>
|
||||
|
||||
<svg id="padsvg1" width="100" height="100">
|
||||
<rect width="10" height="10" />
|
||||
<rect id="transrect1" width="10" height="10" />
|
||||
</svg>
|
||||
|
||||
<pre id="test">
|
||||
|
@ -34,6 +35,10 @@ function runTest() {
|
|||
is(buggy.getCTM().e, 30, "buggy.getCTM().e");
|
||||
is(buggy.getCTM().f, 40, "buggy.getCTM().f");
|
||||
|
||||
var transrect1 = document.getElementById("transrect1");
|
||||
is(transrect1.getCTM().a, 2, "transrect1.getCTM().a");
|
||||
is(transrect1.getCTM().d, 3, "transrect1.getCTM().d");
|
||||
|
||||
var padsvg1 = document.getElementById("padsvg1");
|
||||
is(padsvg1.getScreenCTM().e - padsvg1.getBoundingClientRect().x, 27, "padsvg1.getScreenCTM().e");
|
||||
is(padsvg1.getScreenCTM().f - padsvg1.getBoundingClientRect().y, 43, "padsvg1.getScreenCTM().f");
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<!doctype html>
|
||||
<img src="data:image/svg+xml,<svg width='90px' xmlns='http://www.w3.org/2000/svg'></svg>" style="position: absolute;">
|
||||
<img src="data:image/svg+xml,<svg height='90px' xmlns='http://www.w3.org/2000/svg'></svg>" style="position: absolute;">
|
|
@ -568,4 +568,4 @@ pref(layout.css.column-span.enabled,true) load 1534146.html
|
|||
pref(layout.css.column-span.enabled,true) load 1539017.html
|
||||
load 1539303.html
|
||||
pref(layout.css.column-span.enabled,true) load 1541679.html
|
||||
|
||||
load 1547261.html
|
||||
|
|
|
@ -2410,7 +2410,7 @@ nsIFrame::LogicalSides nsImageFrame::GetLogicalSkipSides(
|
|||
}
|
||||
|
||||
nsresult nsImageFrame::GetIntrinsicImageSize(nsSize& aSize) {
|
||||
if (mIntrinsicSize.width && mIntrinsicSize.width) {
|
||||
if (mIntrinsicSize.width && mIntrinsicSize.height) {
|
||||
aSize.SizeTo(*mIntrinsicSize.width, *mIntrinsicSize.height);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<svg style="width: 500px; height: 500px; border: 1px solid green;">
|
||||
<defs>
|
||||
<mask id="mask">
|
||||
<rect id="square" x="200px" y="250px" width="100px" height="150px" fill="#ffffff" />
|
||||
<rect x="200px" y="250px" width="100px" height="150px" fill="#ffffff" />
|
||||
<rect x="50px" y="105px" width="110px" height="195px" fill="blue" />
|
||||
</mask>
|
||||
</defs>
|
||||
<rect mask="url(#mask)" width="500px" height="500px" fill="red" />
|
||||
|
|
До Ширина: | Высота: | Размер: 287 B После Ширина: | Высота: | Размер: 350 B |
|
@ -1,12 +1,18 @@
|
|||
<style>
|
||||
#square{
|
||||
#square1 {
|
||||
transform: translate(100px, 100px) scale(2,3);
|
||||
}
|
||||
#square2 {
|
||||
transform: scale(2,3);
|
||||
}
|
||||
</style>
|
||||
<svg style="width: 500px; height: 500px; border: 1px solid green;">
|
||||
<defs>
|
||||
<mask id="mask">
|
||||
<rect id="square" x="50px" y="50px" width="50px" height="50px" fill="#ffffff" />
|
||||
<rect id="square1" x="50px" y="50px" width="50px" height="50px" fill="#ffffff" />
|
||||
<svg viewBox="0 0 100 100">
|
||||
<rect id="square2" x="5" y="7" width="11" height="13" fill="blue" />
|
||||
</svg>
|
||||
</mask>
|
||||
</defs>
|
||||
<rect mask="url(#mask)" width="500px" height="500px" fill="red" />
|
||||
|
|
|
@ -156,11 +156,9 @@ function run() {
|
|||
var sheeturl = "data:text/css," + escape(sheet);
|
||||
var link = "<link rel='stylesheet' href='" + sheeturl + "'>";
|
||||
var htmldoc = "<!DOCTYPE HTML>" + link + link + "<body>";
|
||||
var docurl = "data:text/html," + escape(htmldoc);
|
||||
post_clone_test(docurl, function() {
|
||||
var wrappedFrame = SpecialPowers.wrap(iframe);
|
||||
var clonedoc = wrappedFrame.contentDocument;
|
||||
var clonewin = wrappedFrame.contentWindow;
|
||||
post_clone_test(htmldoc, function() {
|
||||
var clonedoc = iframe.contentDocument;
|
||||
var clonewin = iframe.contentWindow;
|
||||
var links = clonedoc.getElementsByTagName("link");
|
||||
// cause a clone
|
||||
var clonedsheet = links[1].sheet;
|
||||
|
@ -891,9 +889,9 @@ function change_state(func)
|
|||
posted_items.push({state: func});
|
||||
}
|
||||
|
||||
function post_clone_test(docurl, testfunc)
|
||||
function post_clone_test(srcdoc, testfunc)
|
||||
{
|
||||
posted_items.push({docurl: docurl, testfunc: testfunc});
|
||||
posted_items.push({srcdoc, testfunc});
|
||||
}
|
||||
|
||||
function handle_posted_items()
|
||||
|
@ -910,9 +908,9 @@ function handle_posted_items()
|
|||
return;
|
||||
}
|
||||
|
||||
var docurl = posted_items[0].docurl;
|
||||
var srcdoc = posted_items[0].srcdoc;
|
||||
iframe.onload = handle_iframe_onload;
|
||||
iframe.src = docurl;
|
||||
iframe.srcdoc = srcdoc;
|
||||
}
|
||||
|
||||
function handle_iframe_onload(event)
|
||||
|
|
|
@ -59,7 +59,7 @@ void nsSVGClipPathFrame::ApplyClipPath(gfxContext& aContext,
|
|||
static_cast<SVGGeometryElement*>(pathFrame->GetContent());
|
||||
|
||||
gfxMatrix toChildsUserSpace =
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(pathFrame, this) *
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(pathFrame) *
|
||||
(GetClipPathTransform(aClippedFrame) * aMatrix);
|
||||
|
||||
gfxMatrix newMatrix = aContext.CurrentMatrixDouble()
|
||||
|
@ -220,8 +220,7 @@ void nsSVGClipPathFrame::PaintFrameIntoMask(nsIFrame* aFrame,
|
|||
nsIContent* childContent = child->GetContent();
|
||||
if (childContent->IsSVGElement()) {
|
||||
toChildsUserSpace =
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(child, child->GetParent()) *
|
||||
mMatrixForChildren;
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(child) * mMatrixForChildren;
|
||||
}
|
||||
|
||||
// clipPath does not result in any image rendering, so we just use a dummy
|
||||
|
@ -302,7 +301,7 @@ bool nsSVGClipPathFrame::PointIsInsideClipPath(nsIFrame* aClippedFrame,
|
|||
if (SVGFrame) {
|
||||
gfxPoint pointForChild = point;
|
||||
|
||||
gfxMatrix m = nsSVGUtils::GetTransformMatrixInUserSpace(kid, this);
|
||||
gfxMatrix m = nsSVGUtils::GetTransformMatrixInUserSpace(kid);
|
||||
if (!m.IsIdentity()) {
|
||||
if (!m.Invert()) {
|
||||
return false;
|
||||
|
@ -428,9 +427,8 @@ gfxMatrix nsSVGClipPathFrame::GetCanvasTM() { return mMatrixForChildren; }
|
|||
gfxMatrix nsSVGClipPathFrame::GetClipPathTransform(nsIFrame* aClippedFrame) {
|
||||
SVGClipPathElement* content = static_cast<SVGClipPathElement*>(GetContent());
|
||||
|
||||
gfxMatrix tm =
|
||||
content->PrependLocalTransformsTo({}, eChildToUserSpace) *
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(this, this->GetParent());
|
||||
gfxMatrix tm = content->PrependLocalTransformsTo({}, eChildToUserSpace) *
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(this);
|
||||
|
||||
SVGAnimatedEnumeration* clipPathUnits =
|
||||
&content->mEnumAttributes[SVGClipPathElement::CLIPPATHUNITS];
|
||||
|
@ -464,7 +462,7 @@ SVGBBox nsSVGClipPathFrame::GetBBoxForClipPathFrame(const SVGBBox& aBBox,
|
|||
nsSVGDisplayableFrame* svg = do_QueryFrame(frame);
|
||||
if (svg) {
|
||||
gfxMatrix matrix =
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(frame, this) * aMatrix;
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(frame) * aMatrix;
|
||||
tmpBBox = svg->GetBBoxContribution(mozilla::gfx::ToMatrix(matrix),
|
||||
nsSVGUtils::eBBoxIncludeFill);
|
||||
nsSVGClipPathFrame* clipPathFrame;
|
||||
|
|
|
@ -261,7 +261,7 @@ void nsSVGDisplayContainerFrame::PaintSVG(gfxContext& aContext,
|
|||
continue; // nothing to paint for kid
|
||||
}
|
||||
|
||||
m = nsSVGUtils::GetTransformMatrixInUserSpace(kid, this) * m;
|
||||
m = nsSVGUtils::GetTransformMatrixInUserSpace(kid) * m;
|
||||
if (m.IsSingular()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -392,8 +392,7 @@ SVGBBox nsSVGDisplayContainerFrame::GetBBoxContribution(
|
|||
if (content->IsSVGElement()) {
|
||||
transform = static_cast<SVGElement*>(content)->PrependLocalTransformsTo(
|
||||
{}, eChildToUserSpace) *
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(kid, this) *
|
||||
transform;
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(kid) * transform;
|
||||
}
|
||||
// We need to include zero width/height vertical/horizontal lines, so we
|
||||
// have to use UnionEdges.
|
||||
|
|
|
@ -118,7 +118,7 @@ already_AddRefed<SourceSurface> nsSVGMaskFrame::GetMaskForMaskedFrame(
|
|||
nsSVGDisplayableFrame* SVGFrame = do_QueryFrame(kid);
|
||||
if (SVGFrame) {
|
||||
SVGFrame->NotifySVGChanged(nsSVGDisplayableFrame::TRANSFORM_CHANGED);
|
||||
m = nsSVGUtils::GetTransformMatrixInUserSpace(kid, this) * m;
|
||||
m = nsSVGUtils::GetTransformMatrixInUserSpace(kid) * m;
|
||||
}
|
||||
|
||||
nsSVGUtils::PaintFrameWithEffects(kid, *tmpCtx, m, aParams.imgParams);
|
||||
|
|
|
@ -361,9 +361,7 @@ already_AddRefed<SourceSurface> nsSVGPatternFrame::PaintPattern(
|
|||
nsSVGDisplayableFrame *SVGFrame = do_QueryFrame(kid);
|
||||
if (SVGFrame) {
|
||||
SVGFrame->NotifySVGChanged(nsSVGDisplayableFrame::TRANSFORM_CHANGED);
|
||||
tm = nsSVGUtils::GetTransformMatrixInUserSpace(kid,
|
||||
patternWithChildren) *
|
||||
tm;
|
||||
tm = nsSVGUtils::GetTransformMatrixInUserSpace(kid) * tm;
|
||||
}
|
||||
|
||||
nsSVGUtils::PaintFrameWithEffects(kid, *ctx, tm, aImgParams);
|
||||
|
|
|
@ -103,7 +103,7 @@ void nsSVGSwitchFrame::PaintSVG(gfxContext& aContext,
|
|||
if (kid) {
|
||||
gfxMatrix tm = aTransform;
|
||||
if (kid->GetContent()->IsSVGElement()) {
|
||||
tm = nsSVGUtils::GetTransformMatrixInUserSpace(kid, this) * tm;
|
||||
tm = nsSVGUtils::GetTransformMatrixInUserSpace(kid) * tm;
|
||||
}
|
||||
nsSVGUtils::PaintFrameWithEffects(kid, aContext, tm, aImgParams,
|
||||
aDirtyRect);
|
||||
|
@ -255,8 +255,7 @@ SVGBBox nsSVGSwitchFrame::GetBBoxContribution(const Matrix& aToBBoxUserspace,
|
|||
if (content->IsSVGElement()) {
|
||||
transform = static_cast<SVGElement*>(content)->PrependLocalTransformsTo(
|
||||
{}, eChildToUserSpace) *
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(kid, this) *
|
||||
transform;
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(kid) * transform;
|
||||
}
|
||||
return svgKid->GetBBoxContribution(ToMatrix(transform), aFlags);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "nsPresContext.h"
|
||||
#include "nsStyleCoord.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsStyleTransformMatrix.h"
|
||||
#include "SVGAnimatedLength.h"
|
||||
#include "nsSVGClipPathFrame.h"
|
||||
#include "nsSVGContainerFrame.h"
|
||||
|
@ -1094,9 +1095,8 @@ gfxRect nsSVGUtils::GetBBox(nsIFrame* aFrame, uint32_t aFlags,
|
|||
matrix = gfxMatrix();
|
||||
}
|
||||
|
||||
matrix = nsSVGUtils::GetTransformMatrixInUserSpace(
|
||||
clipPathFrame, clipPathFrame->GetParent()) *
|
||||
matrix;
|
||||
matrix =
|
||||
nsSVGUtils::GetTransformMatrixInUserSpace(clipPathFrame) * matrix;
|
||||
|
||||
bbox = clipPathFrame->GetBBoxForClipPathFrame(bbox, matrix, aFlags)
|
||||
.ToThebesRect();
|
||||
|
@ -1251,8 +1251,8 @@ bool nsSVGUtils::GetNonScalingStrokeTransform(nsIFrame* aFrame,
|
|||
|
||||
MOZ_ASSERT(aFrame->GetContent()->IsSVGElement(), "should be an SVG element");
|
||||
|
||||
nsSVGOuterSVGFrame* outer = nsSVGUtils::GetOuterSVGFrame(aFrame);
|
||||
*aUserToOuterSVG = nsSVGUtils::GetTransformMatrixInUserSpace(aFrame, outer);
|
||||
*aUserToOuterSVG = ThebesMatrix(SVGContentUtils::GetCTM(
|
||||
static_cast<SVGElement*>(aFrame->GetContent()), true));
|
||||
|
||||
return aUserToOuterSVG->HasNonTranslation();
|
||||
}
|
||||
|
@ -1642,7 +1642,7 @@ void nsSVGUtils::PaintSVGGlyph(Element* aElement, gfxContext* aContext) {
|
|||
if (frame->GetContent()->IsSVGElement()) {
|
||||
// PaintSVG() expects the passed transform to be the transform to its own
|
||||
// SVG user space, so we need to account for any 'transform' attribute:
|
||||
m = nsSVGUtils::GetTransformMatrixInUserSpace(frame, frame->GetParent());
|
||||
m = nsSVGUtils::GetTransformMatrixInUserSpace(frame);
|
||||
}
|
||||
|
||||
// SVG-in-OpenType is not allowed to paint external resources, so we can
|
||||
|
@ -1696,29 +1696,49 @@ gfxMatrix nsSVGUtils::GetCSSPxToDevPxMatrix(nsIFrame* aNonSVGFrame) {
|
|||
return gfxMatrix(devPxPerCSSPx, 0.0, 0.0, devPxPerCSSPx, 0.0, 0.0);
|
||||
}
|
||||
|
||||
gfxMatrix nsSVGUtils::GetTransformMatrixInUserSpace(const nsIFrame* aFrame,
|
||||
const nsIFrame* aAncestor) {
|
||||
gfxMatrix nsSVGUtils::GetTransformMatrixInUserSpace(const nsIFrame* aFrame) {
|
||||
// We check element instead of aFrame directly because SVG element
|
||||
// may have non-SVG frame, <tspan> for example.
|
||||
MOZ_ASSERT(aFrame->GetContent() && aFrame->GetContent()->IsSVGElement(),
|
||||
"Only use this wrapper for SVG elements");
|
||||
|
||||
if (!aFrame->IsTransformed()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
nsDisplayTransform::FrameTransformProperties properties{
|
||||
aFrame, AppUnitsPerCSSPixel(), nullptr};
|
||||
nsStyleTransformMatrix::TransformReferenceBox refBox;
|
||||
refBox.Init(aFrame);
|
||||
|
||||
// SVG elements can have x/y offset, their default transform origin
|
||||
// is the origin of user space, not the top left point of the frame.
|
||||
Point3D svgTransformOrigin{
|
||||
properties.mToTransformOrigin.x - CSSPixel::FromAppUnits(refBox.X()),
|
||||
properties.mToTransformOrigin.y - CSSPixel::FromAppUnits(refBox.Y()),
|
||||
properties.mToTransformOrigin.z};
|
||||
|
||||
Matrix svgTransform;
|
||||
Matrix4x4 trans;
|
||||
(void)aFrame->IsSVGTransformed(&svgTransform);
|
||||
|
||||
if (properties.HasTransform()) {
|
||||
trans = nsStyleTransformMatrix::ReadTransforms(
|
||||
properties.mIndividualTransformList
|
||||
? properties.mIndividualTransformList->mHead
|
||||
: nullptr,
|
||||
properties.mMotion,
|
||||
properties.mTransformList ? properties.mTransformList->mHead : nullptr,
|
||||
refBox, AppUnitsPerCSSPixel());
|
||||
} else {
|
||||
trans = Matrix4x4::From2D(svgTransform);
|
||||
}
|
||||
|
||||
trans.ChangeBasis(svgTransformOrigin);
|
||||
|
||||
Matrix mm;
|
||||
auto trans = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor,
|
||||
nsIFrame::IN_CSS_UNITS);
|
||||
|
||||
trans.ProjectTo2D();
|
||||
trans.CanDraw2D(&mm);
|
||||
gfxMatrix ret = ThebesMatrix(mm);
|
||||
(void)trans.CanDraw2D(&mm);
|
||||
|
||||
float initPositionX = NSAppUnitsToFloatPixels(aFrame->GetPosition().x,
|
||||
AppUnitsPerCSSPixel()),
|
||||
initPositionY = NSAppUnitsToFloatPixels(aFrame->GetPosition().y,
|
||||
AppUnitsPerCSSPixel());
|
||||
|
||||
// Remove the initial displacement to mimic the behavior
|
||||
// of SVGElement::PrependLocalTransformsTo().
|
||||
ret = ret.PreTranslate(-initPositionX, -initPositionY);
|
||||
|
||||
return ret;
|
||||
return ThebesMatrix(mm);
|
||||
}
|
||||
|
|
|
@ -597,11 +597,13 @@ class nsSVGUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* A simple wrapper of nsLayoutUtils::GetTransformToAncestor to avoid
|
||||
* boilerplate code for changing unit and matrix format.
|
||||
* It is a replacement of
|
||||
* SVGElement::PrependLocalTransformsTo(eUserSpaceToParent).
|
||||
* If no CSS transform is involved, they should behave exactly the same;
|
||||
* if there are CSS transforms, this one will take them into account
|
||||
* while SVGElement::PrependLocalTransformsTo won't.
|
||||
*/
|
||||
static gfxMatrix GetTransformMatrixInUserSpace(const nsIFrame* aFrame,
|
||||
const nsIFrame* aAncestor);
|
||||
static gfxMatrix GetTransformMatrixInUserSpace(const nsIFrame* aFrame);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
<Url type="application/x-suggestions+json" method="GET" template="https://www.prisjakt.nu/plugins/opensearch/suggestions.php">
|
||||
<Param name="search" value="{searchTerms}"/>
|
||||
</Url>
|
||||
<Url type="text/html" method="GET" template="https://m.prisjakt.nu/search/{searchTerms}"/>
|
||||
<Url type="text/html" method="GET" template="https://www.prisjakt.nu/search">
|
||||
<Param name="search" value="{searchTerms}"/>
|
||||
</Url>
|
||||
<Url type="application/x-moz-tabletsearch" method="GET" template="https://www.prisjakt.nu/#rparams=ss={searchTerms}"/>
|
||||
</SearchPlugin>
|
||||
|
|
|
@ -63,6 +63,9 @@ add_task(async function test_target_blank_link() {
|
|||
let link = win.document.getElementById("link");
|
||||
|
||||
{
|
||||
// Flush layout so that synthesizeMouseAtCenter on a cross-origin iframe
|
||||
// works as expected.
|
||||
document.body.getBoundingClientRect();
|
||||
synthesizeMouseAtCenter(link, {}, iframe.contentWindow);
|
||||
let {subject: doc} = await promiseObserved("document-element-inserted", doc => doc.documentURI === linkURL);
|
||||
info("Link opened");
|
||||
|
|
|
@ -2144,6 +2144,36 @@ telemetry:
|
|||
- 'main'
|
||||
- 'content'
|
||||
|
||||
ecosystem_old_send_time:
|
||||
bug_numbers:
|
||||
- 1545365
|
||||
description: >
|
||||
The timestamp im milliseconds of the last time we tried to send an Ecosystem ping
|
||||
expires: "73"
|
||||
kind: string
|
||||
notification_emails:
|
||||
- jrediger@mozilla.com
|
||||
release_channel_collection: opt-in
|
||||
record_in_processes:
|
||||
- 'main'
|
||||
record_into_store:
|
||||
- 'pre-account'
|
||||
|
||||
ecosystem_new_send_time:
|
||||
bug_numbers:
|
||||
- 1545365
|
||||
description: >
|
||||
The timestamp im milliseconds of the last time we tried to send an Ecosystem ping
|
||||
expires: "73"
|
||||
kind: string
|
||||
notification_emails:
|
||||
- jrediger@mozilla.com
|
||||
release_channel_collection: opt-in
|
||||
record_in_processes:
|
||||
- 'main'
|
||||
record_into_store:
|
||||
- 'pre-account'
|
||||
|
||||
telemetry.discarded:
|
||||
accumulations:
|
||||
bug_numbers:
|
||||
|
|
|
@ -216,10 +216,21 @@ var EcosystemTelemetry = {
|
|||
this._log.trace(`_submitPing, ping type: ${pingType}, reason: ${reason}`);
|
||||
|
||||
let now = Policy.monotonicNow();
|
||||
let new_send_time = now;
|
||||
let old_send_time = this._lastSendTime;
|
||||
|
||||
// Duration in seconds
|
||||
let duration = Math.round((now - this._lastSendTime) / 1000);
|
||||
this._lastSendTime = now;
|
||||
|
||||
// FIXME(bug 1545365): This is a hack to track the values we see,
|
||||
// in order to determine where negative durations are coming from.
|
||||
// Note: These scalars must be set _before_ getting the rest of the payload.
|
||||
// Note: We don't support signed integer scalars, so we convert these to strings
|
||||
// in order to also capture the negative values.
|
||||
Services.telemetry.scalarSet("telemetry.ecosystem_old_send_time", old_send_time.toString());
|
||||
Services.telemetry.scalarSet("telemetry.ecosystem_new_send_time", new_send_time.toString());
|
||||
|
||||
let payload = this._payload(reason, duration);
|
||||
|
||||
// Never include the client ID.
|
||||
|
|
|
@ -51,6 +51,9 @@ function checkPingStructure(ping, type, reason) {
|
|||
Assert.ok("keyedScalars" in payload, "Payload must contain keyed scalars");
|
||||
Assert.ok("histograms" in payload, "Payload must contain histograms");
|
||||
Assert.ok("keyedHistograms" in payload, "Payload must contain keyed histograms");
|
||||
|
||||
Assert.ok("telemetry.ecosystem_old_send_time" in payload.scalars.parent, "Old send time should be set");
|
||||
Assert.ok("telemetry.ecosystem_new_send_time" in payload.scalars.parent, "New send time should be set");
|
||||
}
|
||||
|
||||
function sendPing() {
|
||||
|
|
|
@ -6700,6 +6700,11 @@ function runTestOnAnotherContext(aPanelOrFrame, aFocusedEditor, aTestName)
|
|||
{
|
||||
aFocusedEditor.value = "";
|
||||
|
||||
// The frames and panel are cross-origin, and we no longer
|
||||
// propagate flushes to parent cross-origin iframes explicitly,
|
||||
// so flush our own layout here so the positions are correct.
|
||||
document.documentElement.getBoundingClientRect();
|
||||
|
||||
var editorRect = synthesizeQueryEditorRect();
|
||||
if (!checkQueryContentResult(editorRect, aTestName + ": editorRect")) {
|
||||
return;
|
||||
|
|
Загрузка…
Ссылка в новой задаче