Merge autoland to central, a=merge

MozReview-Commit-ID: 4TESFjmVSJf
This commit is contained in:
Wes Kocher 2017-05-15 16:04:27 -07:00
commit a2087edbef
105 changed files with 2258 additions and 2109 deletions

View File

@ -78,10 +78,7 @@ browser/extensions/activity-stream/data/content/activity-stream.bundle.js
browser/extensions/activity-stream/vendor/**
# imported from chromium
browser/extensions/mortar/**
# caps/ exclusions
caps/tests/mochitest/browser_checkloaduri.js
# devtools/ exclusions
devtools/client/canvasdebugger/**
devtools/client/commandline/**

View File

@ -1651,3 +1651,5 @@ pref("browser.sessionstore.restore_tabs_lazily", true);
pref("urlclassifier.malwareTable", "goog-malware-shavar,goog-unwanted-shavar,goog-malware-proto,goog-unwanted-proto,test-malware-simple,test-unwanted-simple");
pref("urlclassifier.phishTable", "goog-phish-shavar,goog-phish-proto,test-phish-simple");
#endif
pref("browser.suppress_first_window_animation", true);

View File

@ -114,9 +114,8 @@ a {
fill: #616366;
padding: 0;
border: 1px solid;
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2) transparent;
border-radius: 0 2px 2px 0;
border-inline-start: 1px solid transparent;
box-shadow: 0 0 2px hsla(0,0%,100%,.5) inset,
0 1px 0 hsla(0,0%,100%,.2);
cursor: pointer;
@ -126,8 +125,7 @@ a {
}
#searchSubmit:dir(rtl) {
border-radius: 2px 0 0 2px;
background-image: url("chrome://browser/skin/search-arrow-go-rtl.svg"), linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.1));
transform: scaleX(-1);
}
#searchText:focus + #searchSubmit,
@ -147,13 +145,6 @@ a {
0 1px 0 hsla(210,54%,20%,.03);
}
#searchText:focus + #searchSubmit:dir(rtl),
#searchText[keepfocus] + #searchSubmit:dir(rtl),
#searchText[autofocus] + #searchSubmit:dir(rtl) {
background-image: url("chrome://browser/skin/search-arrow-go-rtl.svg"), linear-gradient(#4cb1ff, #1793e5);
fill: white;
}
#searchText + #searchSubmit:hover {
background-image: url("chrome://browser/skin/search-arrow-go.svg"), linear-gradient(#66bdff, #0d9eff);
fill: white;
@ -163,11 +154,6 @@ a {
0 0 4px hsla(206,100%,20%,.2);
}
#searchText + #searchSubmit:dir(rtl):hover {
background-image: url("chrome://browser/skin/search-arrow-go-rtl.svg"), linear-gradient(#66bdff, #0d9eff);
fill: white;
}
#searchText + #searchSubmit:hover:active {
box-shadow: 0 1px 1px hsla(211,79%,6%,.1) inset,
0 0 1px hsla(211,79%,6%,.2) inset;

View File

@ -307,9 +307,8 @@ body.compact #newtab-search-container {
fill: #616366;
padding: 0;
border: 1px solid;
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2) transparent;
border-radius: 0 2px 2px 0;
border-inline-start: 1px solid transparent;
box-shadow: 0 0 2px hsla(0,0%,100%,.5) inset,
0 1px 0 hsla(0,0%,100%,.2);
cursor: pointer;
@ -319,8 +318,7 @@ body.compact #newtab-search-container {
}
#newtab-search-submit:dir(rtl) {
border-radius: 2px 0 0 2px;
background-image: url("chrome://browser/skin/search-arrow-go-rtl.svg"), linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.1));
transform: scaleX(-1);
}
#newtab-search-text:focus + #newtab-search-submit,
@ -354,14 +352,6 @@ body.compact #newtab-search-container {
transition-duration: 0ms;
}
#newtab-search-text:focus + #newtab-search-submit:dir(rtl),
#newtab-search-text[keepfocus] + #newtab-search-submit:dir(rtl),
#newtab-search-text[autofocus] + #newtab-search-submit:dir(rtl),
#newtab-search-text + #newtab-search-submit:dir(rtl):hover {
background-image: url("chrome://browser/skin/search-arrow-go-rtl.svg"), linear-gradient(#4cb1ff, #1793e5);
fill: white;
}
/* CUSTOMIZE */
#newtab-customize-overlay {
opacity: 0;

View File

@ -756,8 +756,9 @@ const CustomizableWidgets = [
// We need it right now for the case where we re-register the old-style
// main menu panel if photon is disabled at runtime, and we automatically
// put the widgets in there, so they get the right style in the panel.
onAreaNodeRegistered(aArea, aContainer) {
onAreaNodeRegistered: (aArea, aContainer) => {
if (aContainer.ownerDocument == node.ownerDocument &&
aArea == this.currentArea &&
aArea == CustomizableUI.AREA_PANEL) {
updateCombinedWidgetStyle(node, aArea, true);
}
@ -863,8 +864,9 @@ const CustomizableWidgets = [
// We need it right now for the case where we re-register the old-style
// main menu panel if photon is disabled at runtime, and we automatically
// put the widgets in there, so they get the right style in the panel.
onAreaNodeRegistered(aArea, aContainer) {
onAreaNodeRegistered: (aArea, aContainer) => {
if (aContainer.ownerDocument == node.ownerDocument &&
aArea == this.currentArea &&
aArea == CustomizableUI.AREA_PANEL) {
updateCombinedWidgetStyle(node, aArea);
}

View File

@ -382,10 +382,12 @@ this.PanelMultiView = class {
let playTransition = (!!previousViewNode && previousViewNode != viewNode);
let dwu, previousRect;
if (playTransition) {
if (playTransition || this.panelViews) {
dwu = this._dwu;
previousRect = previousViewNode.__lastKnownBoundingRect =
dwu.getBoundsWithoutFlushing(previousViewNode);
if (this.panelViews && !this._mainViewWidth)
this._mainViewWidth = previousRect.width;
}
// Emit the ViewShowing event so that the widget definition has a chance
@ -410,6 +412,8 @@ this.PanelMultiView = class {
}
}
viewNode.setAttribute("current", true);
if (playTransition && this.panelViews)
viewNode.style.maxWidth = viewNode.style.minWidth = this._mainViewWidth + "px";
let evt = new window.CustomEvent("ViewShowing", { bubbles: true, cancelable: true, detail });
viewNode.dispatchEvent(evt);

View File

@ -576,7 +576,12 @@ nsBrowserContentHandler.prototype = {
// The global PB Service consumes this flag, so only eat it in per-window
// PB builds.
if (PrivateBrowsingUtils.isInTemporaryAutoStartMode) {
this.mFeatures = ",private";
this.mFeatures += ",private";
}
if (Services.prefs.getBoolPref("browser.suppress_first_window_animation") &&
!Services.wm.getMostRecentWindow("navigator:browser")) {
this.mFeatures += ",suppressanimation";
}
}

View File

@ -16,6 +16,9 @@ Cu.import("resource://gre/modules/AsyncPrefs.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils", "@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils");
XPCOMUtils.defineLazyServiceGetter(this, "AlertsService", "@mozilla.org/alerts-service;1", "nsIAlertsService");
XPCOMUtils.defineLazyGetter(this, "WeaveService", () =>
Cc["@mozilla.org/weave/service;1"].getService().wrappedJSObject
);
// lazy module getters
@ -973,6 +976,10 @@ BrowserGlue.prototype = {
AutoCompletePopup.init();
DateTimePickerHelper.init();
// Check if Sync is configured
if (Services.prefs.prefHasUserValue("services.sync.username")) {
WeaveService.init();
}
this._firstWindowTelemetry(aWindow);
this._firstWindowLoaded();

View File

@ -122,63 +122,6 @@
background-color: -moz-Dialog;
}
/* Places toolbar */
toolbarbutton.bookmark-item:not(.subviewbutton),
#personal-bookmarks[cui-areatype="toolbar"]:not([overflowedItem=true]) > #bookmarks-toolbar-placeholder {
margin: 0;
padding: 2px 3px;
}
toolbarbutton.bookmark-item:not(.subviewbutton):not(:hover):not(:active):not([open]) {
color: inherit;
}
toolbarbutton.bookmark-item:not(.subviewbutton) {
-moz-appearance: none;
border: 1px solid transparent;
border-radius: 2px;
transition-property: background-color, border-color;
transition-duration: 150ms;
}
toolbarbutton.bookmark-item:not(.subviewbutton):hover:not([open]) {
background: var(--toolbarbutton-hover-background);
border-color: var(--toolbarbutton-hover-bordercolor);
}
toolbarbutton.bookmark-item:not(.subviewbutton):hover:active,
toolbarbutton.bookmark-item[open="true"] {
background: var(--toolbarbutton-active-background);
box-shadow: var(--toolbarbutton-active-boxshadow);
border-color: var(--toolbarbutton-active-bordercolor);
}
toolbarbutton.bookmark-item:not(.subviewbutton):hover:-moz-lwtheme {
background: var(--toolbarbutton-hover-background);
border-color: var(--toolbarbutton-hover-bordercolor);
}
.bookmark-item > .toolbarbutton-icon,
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
/* Force the display of the label for bookmarks */
.bookmark-item > .toolbarbutton-text,
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-text {
display: -moz-box !important;
}
.bookmark-item > .toolbarbutton-menu-dropmarker {
display: none;
}
/* Dropmarker for folder bookmarks */
.bookmark-item[container] > .toolbarbutton-menu-dropmarker {
display: -moz-box !important;
}
#bookmarks-toolbar-placeholder {
list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important;
}

View File

@ -313,84 +313,11 @@ toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon {
/* ----- BOOKMARK BUTTONS ----- */
toolbarbutton.bookmark-item:not(.subviewbutton),
#personal-bookmarks[cui-areatype="toolbar"]:not([overflowedItem=true]) > #bookmarks-toolbar-placeholder {
border: 0;
border-radius: 10000px;
padding: 1px 8px;
margin: 0 0 1px;
}
#personal-bookmarks[cui-areatype="toolbar"]:not([overflowedItem=true]) > #bookmarks-toolbar-placeholder {
-moz-box-orient: horizontal;
}
.bookmark-item > .toolbarbutton-menu-dropmarker {
list-style-image: url("chrome://browser/skin/places/folderDropArrow.png");
-moz-image-region: rect(0, 7px, 5px, 0);
list-style-image: url("chrome://browser/skin/places/arrow-down.svg");
fill: currentColor;
margin-top: 1px;
margin-inline-start: 3px;
margin-inline-end: -2px;
}
@media (min-resolution: 2dppx) {
.bookmark-item > .toolbarbutton-menu-dropmarker {
list-style-image: url("chrome://browser/skin/places/folderDropArrow@2x.png");
-moz-image-region: rect(0, 14px, 10px, 0);
}
.bookmark-item > .toolbarbutton-menu-dropmarker > .dropmarker-icon {
width: 7px;
}
}
.bookmark-item > .toolbarbutton-text,
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-text {
display: -moz-box !important; /* Force the display of the label for bookmarks */
}
toolbarbutton.bookmark-item:not(.subviewbutton):hover {
background-color: rgba(0, 0, 0, .205);
}
toolbarbutton.bookmark-item:hover:not(.subviewbutton),
toolbarbutton.bookmark-item[open="true"]:not(.subviewbutton) {
color: #FFF !important;
text-shadow: 0 1px rgba(0, 0, 0, .4) !important;
}
.bookmark-item:hover > .toolbarbutton-menu-dropmarker,
.bookmark-item[open="true"] > .toolbarbutton-menu-dropmarker {
-moz-image-region: rect(5px, 7px, 10px, 0);
}
@media (min-resolution: 2dppx) {
.bookmark-item:hover > .toolbarbutton-menu-dropmarker,
.bookmark-item[open="true"] > .toolbarbutton-menu-dropmarker {
-moz-image-region: rect(10px, 14px, 20px, 0);
}
}
toolbarbutton.bookmark-item:not(.subviewbutton):active:hover,
toolbarbutton.bookmark-item:not(.subviewbutton)[open="true"] {
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.4), 0 1px rgba(255, 255, 255, 0.4);
background-color: rgba(0, 0, 0, .5);
}
toolbarbutton.bookmark-item > menupopup {
margin-inline-start: 3px;
}
.bookmark-item > .toolbarbutton-icon,
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
width: 16px;
min-height: 16px;
max-height: 16px;
}
.bookmark-item > .toolbarbutton-icon[label]:not([label=""]),
.bookmark-item > .toolbarbutton-icon[type="menu"] {
margin-inline-end: 5px;
}
.bookmark-item[container] {

View File

@ -87,8 +87,6 @@ browser.jar:
skin/classic/browser/places/history@2x.png (places/history@2x.png)
skin/classic/browser/places/toolbar.png (places/toolbar.png)
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
skin/classic/browser/places/folderDropArrow.png (places/folderDropArrow.png)
skin/classic/browser/places/folderDropArrow@2x.png (places/folderDropArrow@2x.png)
skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
skin/classic/browser/places/starred48.png (places/starred48.png)
skin/classic/browser/places/starred48@2x.png (places/starred48@2x.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 443 B

View File

@ -335,6 +335,7 @@ panelview:not([mainview]) .toolbarbutton-text,
photonpanelmultiview panelview {
background: var(--arrowpanel-background);
padding: 6px 0;
min-width: @menuPanelWidth@;
}
photonpanelmultiview panelview[title] {

View File

@ -142,7 +142,6 @@
skin/classic/browser/search-history-icon.svg (../shared/search/history-icon.svg)
skin/classic/browser/search-indicator-magnifying-glass.svg (../shared/search/search-indicator-magnifying-glass.svg)
skin/classic/browser/search-arrow-go.svg (../shared/search/search-arrow-go.svg)
skin/classic/browser/search-arrow-go-rtl.svg (../shared/search/search-arrow-go-rtl.svg)
skin/classic/browser/gear.svg (../shared/search/gear.svg)
skin/classic/browser/tabbrowser/connecting.png (../shared/tabbrowser/connecting.png)
skin/classic/browser/tabbrowser/connecting@2x.png (../shared/tabbrowser/connecting@2x.png)
@ -175,6 +174,9 @@
skin/classic/browser/panic-panel/header-small@2x.png (../shared/panic-panel/header-small@2x.png)
skin/classic/browser/panic-panel/icons.png (../shared/panic-panel/icons.png)
skin/classic/browser/panic-panel/icons@2x.png (../shared/panic-panel/icons@2x.png)
#ifndef XP_LINUX
skin/classic/browser/places/arrow-down.svg (../shared/places/arrow-down.svg)
#endif
skin/classic/browser/places/bookmarks-notification-finish.png (../shared/places/bookmarks-notification-finish.png)
skin/classic/browser/places/bookmarks-notification-finish@2x.png (../shared/places/bookmarks-notification-finish@2x.png)
skin/classic/browser/privatebrowsing/aboutPrivateBrowsing.css (../shared/privatebrowsing/aboutPrivateBrowsing.css)

View File

@ -0,0 +1,6 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
<path fill="context-fill" d="M0 2h8L4 6 0 2z"/>
</svg>

After

Width:  |  Height:  |  Size: 349 B

View File

@ -1,8 +0,0 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="16" height="16" viewBox="0 0 16 16">
<path fill="context-fill" d="M15,7V9.2C15,9.8,14.6,10,14,10H6.5L9.5,13.1C9.9,13.4,9.9,14.1,9.5,14.5L8.7,15.3C8.3,15.7,7.7,15.7,7.3,15.3L0.7,8.7C0.3,8.3,0.3,7.7,0.7,7.3L7.3,0.7C7.7,0.3,8.3,0.3,8.7,0.7L9.5,1.6C9.9,2,9.9,2.6,9.5,3L6.5,6H14C14.6,6,15,6.4,15,7Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 571 B

View File

@ -17,11 +17,19 @@ toolbar[brighttext] :-moz-any(@primaryToolbarButtons@) {
list-style-image: url("chrome://browser/skin/back-large.svg");
}
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
transform: scaleX(-1);
}
#forward-button {
list-style-image: url("chrome://browser/skin/forward.svg");
}
%ifdef MOZ_PHOTON_THEME
#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
transform: scaleX(-1);
}
#reload-button {
list-style-image: url("chrome://browser/skin/reload.svg");
}

View File

@ -146,6 +146,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
@conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon,
%endif
.findbar-button > .toolbarbutton-text,
toolbarbutton.bookmark-item:not(.subviewbutton),
#nav-bar .toolbarbutton-1 > .toolbarbutton-icon,
#nav-bar .toolbarbutton-1 > .toolbarbutton-text,
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-stack,
@ -256,6 +257,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
.tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled=true]):hover,
.tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled=true]):hover,
.findbar-button:not(:-moz-any([checked="true"],[disabled="true"])):hover > .toolbarbutton-text,
toolbarbutton.bookmark-item:not(.subviewbutton):hover:not([disabled="true"]):not([open]),
#nav-bar .toolbarbutton-1:not([disabled=true]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
@ -272,6 +274,8 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
}
.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
toolbarbutton.bookmark-item:not(.subviewbutton):hover:active:not([disabled="true"]),
toolbarbutton.bookmark-item[open="true"],
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open]) > .toolbarbutton-icon,
#nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
@ -362,10 +366,6 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
padding: 7px !important;
}
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
transform: scaleX(-1);
}
%ifdef MOZ_PHOTON_THEME
#back-button:not(:hover):not(:active):not([open=true]) > .toolbarbutton-icon,
#back-button[disabled=true] > .toolbarbutton-icon {
@ -396,3 +396,27 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
margin-bottom: -20px;
}
/* ::::: bookmark buttons ::::: */
toolbarbutton.bookmark-item:not(.subviewbutton) {
margin: 0;
padding: 2px 3px;
-moz-appearance: none;
}
.bookmark-item > .toolbarbutton-icon,
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
/* Force the display of the label for bookmarks */
.bookmark-item > .toolbarbutton-text,
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-text {
display: -moz-box !important;
}
.bookmark-item > .toolbarbutton-icon[label]:not([label=""]),
.bookmark-item > .toolbarbutton-icon[type="menu"] {
margin-inline-end: 5px;
}

View File

@ -371,45 +371,11 @@ toolbar[brighttext] {
/* ::::: bookmark buttons ::::: */
toolbarbutton.bookmark-item:not(.subviewbutton),
#personal-bookmarks[cui-areatype="toolbar"]:not([overflowedItem=true]) > #bookmarks-toolbar-placeholder {
margin: 0;
padding: 2px 3px;
-moz-appearance: none;
border: 1px solid transparent;
border-radius: var(--toolbarbutton-border-radius);
background-origin: padding-box !important;
background-clip: padding-box !important;
transition-property: background-color, border-color, box-shadow;
transition-duration: 150ms;
}
toolbarbutton.bookmark-item:not(.subviewbutton):hover:not([disabled="true"]):not([open]) {
border-color: var(--toolbarbutton-hover-bordercolor);
background: var(--toolbarbutton-hover-background);
}
toolbarbutton.bookmark-item:not(.subviewbutton):hover:active:not([disabled="true"]),
toolbarbutton.bookmark-item[open="true"] {
border-color: var(--toolbarbutton-active-bordercolor);
box-shadow: var(--toolbarbutton-active-boxshadow);
background: var(--toolbarbutton-active-background);
}
.bookmark-item > .toolbarbutton-icon,
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
/* Force the display of the label for bookmarks */
.bookmark-item > .toolbarbutton-text,
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-text {
display: -moz-box !important;
}
.bookmark-item > .toolbarbutton-menu-dropmarker {
display: none;
list-style-image: url("chrome://browser/skin/places/arrow-down.svg");
fill: currentColor;
margin-top: 1px;
margin-inline-start: 3px;
}
#bookmarks-toolbar-placeholder {

View File

@ -261,9 +261,13 @@ add_task(function* () {
browser,
testURL.toString(),
function* (testURLFn) {
// eslint-disable-next-line no-shadow , no-eval
let testURL = eval("(" + testURLFn + ")");
// eslint-disable-next-line no-shadow
let ssm = Services.scriptSecurityManager;
// eslint-disable-next-line no-shadow
let baseFlags = ssm.STANDARD | ssm.DONT_REPORT_ERRORS;
// eslint-disable-next-line no-unused-vars
let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
let b = new content.Blob(["I am a blob"]);
let contentBlobURI = content.URL.createObjectURL(b);

View File

@ -37,3 +37,4 @@
* [Chrome mochitests](tests/mochitest-chrome.md)
* [DevTools mochitests](tests/mochitest-devtools.md)
* [Writing tests](tests/writing-tests.md)
* [Debugging intermittent failures](tests/debugging-intermittents.md)

View File

@ -0,0 +1,67 @@
# Debugging intermittent test failures
While working on automated tests, you will inevitably encounter intermittent test failures, also called "oranges" here.
This page documents some tips for finding and debugging these test failures.
## Finding Intermittents
Normally you will have no trouble finding out that a particular test is intermittent, because a bug will be filed and you will see it through the normal mechanisms.
However, it can still be useful to see intermittents in context. The [War on Oranges site](https://brasstacks.mozilla.com/orangefactor/) shows intermittents ranked by frequency. The orange factor robot also posts weekly updates to the relevant bugs in Bugzilla (see [an example here](https://bugzilla.mozilla.org/show_bug.cgi?id=1250523#c4)).
You can also see oranges in Bugzilla. Go to [the settings page](https://bugzilla.mozilla.org/userprefs.cgi?tab=settings) and enable "When viewing a bug, show its corresponding Orange Factor page".
## Reproducing Test Failures locally
The first step to fix an orange is to reproduce it.
If a test fails at different places for each failure it might be a timeout. The current mochitest timeout is 45 seconds, so if successful runs of an intermittent are ~40 seconds, it might just be a
real timeout. This is particularly true if the failure is most often seen on the slower builds, for example Linux 32 debug. In this case you can either split the test or call `requestLongerTimeout`.
Sometimes reproducing can only be done in automation, but it's worth trying locally, because this makes it much simpler to debug.
First, try running the test in isolation. You can use the `--repeat` and `--run-until-failure` flags to `mach mochitest` to automate this a bit. It's nice to do this sort of thing in a VM (or using Xnest on Linux) to avoid locking up your machine. Mozilla provides an [easy-to-use VM](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Using_the_VM).
Sometimes, though, a test will only fail if it is run in conjunction with one or more other tests. You can use the `--start-at` and `--end-at` flags with `mach mochitest` to run a group of tests together.
For some jobs, but not all, you can get an [interactive shell from TaskCluster](https://jonasfj.dk/2016/03/one-click-loaners-with-taskcluster/).
There's also a [handy page of e10s test debugging tips](https://wiki.mozilla.org/Electrolysis/e10s_test_tips) that is worth a read.
Because intermittents are often caused by race conditions, it's sometimes useful to enable Chaos Mode. This changes timings and event orderings a bit. The simplest way to do this is to enable it in a specific test, by
calling `SimpleTest.testInChaosMode`. You can also set the `MOZ_CHAOSMODE` environment variable, or even edit `mfbt/ChaosMode.cpp` directly.
Some tests leak intermittently. Use `ac_add_options --enable-logrefcnt` in your mozconfig to potentially find them.<!--TODO: how? add more detail about this -->
The `rr` tool has [its own chaos mode](http://robert.ocallahan.org/2016/02/introducing-rr-chaos-mode.html). This can also sometimes reproduce a failure that isn't ordinarily reproducible. While it's difficult to debug JS bugs using `rr`, often if you can reliably reproduce the failure you can at least experiment (see below) to attempt a fix.
## That Didn't Work
If you couldn't reproduce locally, there are other options.
One useful approach is to add additional logging to the test, then push again. Sometimes log buffering makes the output weird; you can add a call to `SimpleTest.requestCompleteLog()` to fix this.
You can run a single directory of tests on try using `mach try DIR`. You can also use the `--rebuild` flag to retrigger test jobs multiple times; or you can also do this easily from treeherder.<!--TODO: how? and why is it easy?-->
## Solving
Sometimes the problem is a race at a specific spot in the test. You can test this theory by adding a short wait to see if the failure goes away, like:
```javascript
yield new Promise(r => setTimeout(r, 100));
```
See the `waitForTick` and `waitForTime` functions in `DevToolsUtils` for similar functionality.
You can use a similar trick to "pause" the test at a certain point. This is useful when debugging locally because it will leave Firefox open and responsive, at the specific spot you've chosen. Do this
using `yield new Promise(r => r);`.
`shared-head.js` also has some helpers, like `once`, to bind to events with additional logging.
You can also binary search the test by either commenting out chunks of it, or hacking in early `return`s. You can do a bunch of these experiments in parallel without waiting for the first to complete.
## Verifying
It's difficult to verify that an intermittent has truly been fixed.
One thing you can do is push to try, and then retrigger the job many times in treeherder. Exactly how many times you should retrigger depends on the frequency of the failure.

View File

@ -133,6 +133,45 @@ private:
nsTextEditorState* mTextEditorState;
};
class MOZ_RAII AutoRestoreEditorState final
{
public:
explicit AutoRestoreEditorState(nsIEditor* aEditor,
nsIPlaintextEditor* aPlaintextEditor
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mEditor(aEditor)
, mPlaintextEditor(aPlaintextEditor)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
MOZ_ASSERT(mEditor);
MOZ_ASSERT(mPlaintextEditor);
uint32_t flags;
mEditor->GetFlags(&mSavedFlags);
flags = mSavedFlags;
flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
flags |= nsIPlaintextEditor::eEditorDontEchoPassword;
mEditor->SetFlags(flags);
mPlaintextEditor->GetMaxTextLength(&mSavedMaxLength);
mPlaintextEditor->SetMaxTextLength(-1);
}
~AutoRestoreEditorState()
{
mPlaintextEditor->SetMaxTextLength(mSavedMaxLength);
mEditor->SetFlags(mSavedFlags);
}
private:
nsIEditor* mEditor;
nsIPlaintextEditor* mPlaintextEditor;
uint32_t mSavedFlags;
int32_t mSavedMaxLength;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/*static*/
bool
nsITextControlElement::GetWrapPropertyEnum(nsIContent* aContent,
@ -2551,8 +2590,9 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
if (domSel)
{
selPriv = do_QueryInterface(domSel);
if (selPriv)
if (selPriv) {
selPriv->StartBatchChanges();
}
}
nsCOMPtr<nsISelectionController> kungFuDeathGrip = mSelCon.get();
@ -2577,34 +2617,25 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
valueSetter.Init();
// get the flags, remove readonly and disabled, set the value,
// restore flags
uint32_t flags, savedFlags;
mEditor->GetFlags(&savedFlags);
flags = savedFlags;
flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
flags |= nsIPlaintextEditor::eEditorDontEchoPassword;
mEditor->SetFlags(flags);
// get the flags, remove readonly, disabled and max-length,
// set the value, restore flags
{
AutoRestoreEditorState restoreState(mEditor, plaintextEditor);
mTextListener->SettingValue(true);
bool notifyValueChanged = !!(aFlags & eSetValue_Notify);
mTextListener->SetValueChanged(notifyValueChanged);
mTextListener->SettingValue(true);
bool notifyValueChanged = !!(aFlags & eSetValue_Notify);
mTextListener->SetValueChanged(notifyValueChanged);
// Also don't enforce max-length here
int32_t savedMaxLength;
plaintextEditor->GetMaxTextLength(&savedMaxLength);
plaintextEditor->SetMaxTextLength(-1);
if (insertValue.IsEmpty()) {
mEditor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
} else {
plaintextEditor->InsertText(insertValue);
}
if (insertValue.IsEmpty()) {
mEditor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
} else {
plaintextEditor->InsertText(insertValue);
mTextListener->SetValueChanged(true);
mTextListener->SettingValue(false);
}
mTextListener->SetValueChanged(true);
mTextListener->SettingValue(false);
if (!weakFrame.IsAlive()) {
// If the frame was destroyed because of a flush somewhere inside
// InsertText, mBoundFrame here will be false. But it's also possible
@ -2623,10 +2654,9 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
}
}
plaintextEditor->SetMaxTextLength(savedMaxLength);
mEditor->SetFlags(savedFlags);
if (selPriv)
if (selPriv) {
selPriv->EndBatchChanges();
}
}
}
} else {

View File

@ -775,17 +775,22 @@ var gMetadataTests = [
},
{ name:"wavedata_u8.wav", tags: { }
},
{ name:"flac-s24.flac", tags: {
ALBUM:"Seascapes",
TITLE:"(La Mer) - II. Jeux de vagues. Allegro",
COMPOSER:"Debussy, Claude",
TRACKNUMBER:"2/9",
DISCNUMBER:"1/1",
encoder:"Lavf57.41.100",
}
},
];
// Now Fennec doesn't support flac, so only test it on non-android platforms.
if (getAndroidVersion() < 0) {
gMetadataTests = gMetadataTests.concat([
{ name:"flac-s24.flac", tags: {
ALBUM:"Seascapes",
TITLE:"(La Mer) - II. Jeux de vagues. Allegro",
COMPOSER:"Debussy, Claude",
TRACKNUMBER:"2/9",
DISCNUMBER:"1/1",
encoder:"Lavf57.41.100",
}
}]);
}
// Test files for Encrypted Media Extensions
var gEMETests = [
{

View File

@ -870,7 +870,6 @@ skip-if = android_version == '17' # android(bug 1232305)
[test_mediatrack_replay_from_end.html]
skip-if = toolkit == 'android' # android(bug 1232305)
[test_metadata.html]
skip-if = toolkit == 'android' # android(bug 1232305)
[test_mixed_principals.html]
skip-if = toolkit == 'android' # bug 1309814, android(bug 1232305)
[test_mozHasAudio.html]

View File

@ -16,6 +16,7 @@
#include "skia/include/core/SkTypeface.h"
#include "skia/include/effects/SkGradientShader.h"
#include "skia/include/core/SkColorFilter.h"
#include "skia/include/core/SkRegion.h"
#include "skia/include/effects/SkBlurImageFilter.h"
#include "skia/include/effects/SkLayerRasterizer.h"
#include "skia/src/core/SkDevice.h"

View File

@ -95,7 +95,9 @@ void
ServoRestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
nsRestyleHint aRestyleHint)
{
NS_WARNING("stylo: ServoRestyleManager::PostRebuildAllStyleDataEvent not implemented");
// TODO(emilio): We should do the stylesheet flushing + device reset async
// here.
RebuildAllStyleData(aExtraHint, aRestyleHint);
}
/* static */ void

View File

@ -1981,8 +1981,8 @@ fuzzy(8,1900) == 1291528.html 1291528-ref.html
fuzzy(255,1000) skip-if(!cocoaWidget) == 1294102-1.html 1294102-1-ref.html
random-if(Android) fuzzy-if(skiaContent,15,50) == 1295466-1.xhtml 1295466-1-ref.xhtml #bug 982547
fuzzy-if(Android,27,874) fuzzy-if(gtkWidget,14,29) == 1313772.xhtml 1313772-ref.xhtml # Bug 1128229
fuzzy(2,320000) fails-if(stylo) == 1315113-1.html 1315113-1-ref.html
fuzzy(2,20000) fails-if(stylo) == 1315113-2.html 1315113-2-ref.html
fuzzy(2,320000) == 1315113-1.html 1315113-1-ref.html
fuzzy(2,20000) == 1315113-2.html 1315113-2-ref.html
== 1315632-1.html 1315632-1-ref.html
fuzzy(2,40000) == 1316719-1a.html 1316719-1-ref.html
fuzzy(2,40000) == 1316719-1b.html 1316719-1-ref.html

View File

@ -16,7 +16,7 @@ fails-if(stylo) == linear-diagonal-3c.html linear-diagonal-3-ref.html
fails-if(stylo) == linear-diagonal-4a.html linear-diagonal-4-ref.html
fails-if(stylo) == linear-diagonal-4b.html linear-diagonal-4-ref.html
fails-if(stylo) == linear-diagonal-4c.html linear-diagonal-4-ref.html
fails-if(stylo) == linear-premul.html linear-premul-ref.html
== linear-premul.html linear-premul-ref.html
# these tests uses a similar gradient over different bounds. It's perfectly
# reasonable to expect implementations to give slightly different results

View File

@ -75,7 +75,7 @@ fails-if(stylo) HTTP(..) == enable-sheet-4.html enable-sheet-4-ref.html # bug 13
skip-if(stylo) HTTP(..) == enable-sheet-5.html enable-sheet-4-ref.html
skip HTTP(..) == enable-sheet-6.html multiple-in-family-1-ref.html
skip HTTP(..) == enable-sheet-7.html multiple-in-family-1-ref.html
fails-if(stylo) HTTP(..) == disable-sheet-1.html disable-sheet-1-ref.html
HTTP(..) == disable-sheet-1.html disable-sheet-1-ref.html
# We're missing disable-sheet-{2,3,6,7} (analogs to
# enable-sheet{2,3,6,7}) because I don't know how to detect test
# completion for those cases.

View File

@ -1,7 +1,7 @@
default-preferences pref(layout.css.font-loading-api.enabled,true)
fails-if(stylo) HTTP(..) == dynamic-insert-1.html dynamic-insert-1-ref.html
fails-if(stylo) HTTP(..) == dynamic-remove-1.html dynamic-remove-1-ref.html
HTTP(..) == dynamic-insert-1.html dynamic-insert-1-ref.html
HTTP(..) == dynamic-remove-1.html dynamic-remove-1-ref.html
fails-if(stylo) HTTP(..) == ex-unit-1.html ../font-face/ex-unit-1-ref.html
fuzzy-if(skiaContent,2,10) HTTP(..) == multiple-sets-1.html multiple-sets-1-ref.html
HTTP(..) == name-collision.html ../font-face/name-collision-ref.html

View File

@ -1,2 +1,2 @@
fails-if(stylo) == default-style.html default-style-ref.html
== default-style.html default-style-ref.html
== default-style-dyn.html default-style-dyn-ref.html

View File

@ -24,7 +24,7 @@ include default-style/reftest.list
# Tests for bugs:
== block-invalidate.html block-invalidate-ref.html
== in-cells.html in-cells-ref.html
fails-if(stylo) == max-height.html max-height-ref.html
== max-height.html max-height-ref.html
# Tests for block and inline orientation in combination with writing-mode
!= meter-orient-vertical.html meter-orient-horizontal.html

View File

@ -6,11 +6,11 @@
== background-draw-nothing-malformed-images.html background-draw-nothing-ref.html
== background-monster-rect.html background-monster-rect-ref.html
== background-over-size-rect.html background-over-size-rect-ref.html
fails-if(stylo) == background-test-parser.html background-test-parser-ref.html
== background-test-parser.html background-test-parser-ref.html
fuzzy-if(Android,113,124) == background-with-other-properties.html background-with-other-properties-ref.html
fuzzy-if(Android,16,22) == background-zoom-1.html background-zoom-1-ref.html # Bug 1128229
== background-zoom-2.html background-zoom-2-ref.html
== background-zoom-3.html background-zoom-3-ref.html
== background-zoom-4.html background-zoom-4-ref.html
fails-if(stylo) == dom-api-computed-style.html dom-api-ref.html
fails-if(stylo) == dom-api.html dom-api-ref.html
== dom-api-computed-style.html dom-api-ref.html
== dom-api.html dom-api-ref.html

View File

@ -5,16 +5,16 @@ default-preferences pref(layout.css.prefixes.webkit,true)
# In this test, we don't render a "-webkit-gradient" exactly correctly.
# (It's just here to ensure that our approximate/do-something rendering doesn't
# change unexpectedly.)
fails-if(stylo) == webkit-gradient-approx-radial-1.html webkit-gradient-approx-radial-1-ref.html
== webkit-gradient-approx-radial-1.html webkit-gradient-approx-radial-1-ref.html
# Tests for -webkit-gradient(linear, ...)
fails-if(stylo) == webkit-gradient-linear-1a.html webkit-gradient-linear-1-ref.html
fails-if(stylo) == webkit-gradient-linear-1b.html webkit-gradient-linear-1-ref.html
fails-if(stylo) == webkit-gradient-linear-1c.html webkit-gradient-linear-1-ref.html
fails-if(stylo) == webkit-gradient-linear-1d.html webkit-gradient-linear-1-ref.html
== webkit-gradient-linear-1a.html webkit-gradient-linear-1-ref.html
== webkit-gradient-linear-1b.html webkit-gradient-linear-1-ref.html
== webkit-gradient-linear-1c.html webkit-gradient-linear-1-ref.html
== webkit-gradient-linear-1d.html webkit-gradient-linear-1-ref.html
fails-if(stylo) == webkit-gradient-linear-2.html webkit-gradient-linear-2-ref.html
# Tests for -webkit-gradient(radial, ...)
fails-if(stylo) == webkit-gradient-radial-1a.html webkit-gradient-radial-1-ref.html
fails-if(stylo) == webkit-gradient-radial-1b.html webkit-gradient-radial-1-ref.html
fails-if(stylo) == webkit-gradient-radial-2.html webkit-gradient-radial-2-ref.html
== webkit-gradient-radial-1a.html webkit-gradient-radial-1-ref.html
== webkit-gradient-radial-1b.html webkit-gradient-radial-1-ref.html
== webkit-gradient-radial-2.html webkit-gradient-radial-2-ref.html

View File

@ -30,7 +30,8 @@ SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetStrong,
const nsACString* data,
mozilla::css::SheetParsingMode parsing_mode,
const RawServoMediaList* media_list,
RawGeckoURLExtraData* extra_data)
RawGeckoURLExtraData* extra_data,
uint32_t line_number_offset)
SERVO_BINDING_FUNC(Servo_ImportRule_GetSheet,
RawServoStyleSheetStrong,
const RawServoImportRuleBorrowed import_rule)
@ -40,7 +41,8 @@ SERVO_BINDING_FUNC(Servo_StyleSheet_ClearAndUpdate,
mozilla::css::Loader* loader,
mozilla::ServoStyleSheet* gecko_stylesheet,
const nsACString* data,
RawGeckoURLExtraData* extra_data)
RawGeckoURLExtraData* extra_data,
uint32_t line_number_offset)
SERVO_BINDING_FUNC(Servo_StyleSheet_HasRules, bool,
RawServoStyleSheetBorrowed sheet)
SERVO_BINDING_FUNC(Servo_StyleSheet_GetRules, ServoCssRulesStrong,
@ -100,7 +102,8 @@ SERVO_BINDING_FUNC(Servo_CssRules_DeleteRule, nsresult,
#define BASIC_RULE_FUNCS(type_) \
SERVO_BINDING_FUNC(Servo_CssRules_Get##type_##RuleAt, \
RawServo##type_##RuleStrong, \
ServoCssRulesBorrowed rules, uint32_t index) \
ServoCssRulesBorrowed rules, uint32_t index, \
uint32_t* line, uint32_t* column) \
SERVO_BINDING_FUNC(Servo_##type_##Rule_Debug, void, \
RawServo##type_##RuleBorrowed rule, nsACString* result) \
SERVO_BINDING_FUNC(Servo_##type_##Rule_GetCssText, void, \

View File

@ -2095,9 +2095,9 @@ Gecko_CSSKeywordString(nsCSSKeyword aKeyword, uint32_t* aLength)
}
nsCSSFontFaceRule*
Gecko_CSSFontFaceRule_Create()
Gecko_CSSFontFaceRule_Create(uint32_t aLine, uint32_t aColumn)
{
RefPtr<nsCSSFontFaceRule> rule = new nsCSSFontFaceRule(0, 0);
RefPtr<nsCSSFontFaceRule> rule = new nsCSSFontFaceRule(aLine, aColumn);
return rule.forget().take();
}

View File

@ -515,7 +515,7 @@ const char* Gecko_CSSKeywordString(nsCSSKeyword keyword, uint32_t* len);
// Font face rule
// Creates and returns a new (already-addrefed) nsCSSFontFaceRule object.
nsCSSFontFaceRule* Gecko_CSSFontFaceRule_Create();
nsCSSFontFaceRule* Gecko_CSSFontFaceRule_Create(uint32_t line, uint32_t column);
void Gecko_CSSFontFaceRule_GetCssText(const nsCSSFontFaceRule* rule, nsAString* result);
NS_DECL_FFI_REFCOUNTING(nsCSSFontFaceRule, CSSFontFaceRule);

View File

@ -84,8 +84,12 @@ ServoCSSRuleList::GetRule(uint32_t aIndex)
switch (rule) {
#define CASE_RULE(const_, name_) \
case nsIDOMCSSRule::const_##_RULE: { \
ruleObj = new Servo##name_##Rule( \
Servo_CssRules_Get##name_##RuleAt(mRawRules, aIndex).Consume()); \
uint32_t line = 0, column = 0; \
RefPtr<RawServo##name_##Rule> rule = \
Servo_CssRules_Get##name_##RuleAt( \
mRawRules, aIndex, &line, &column \
).Consume(); \
ruleObj = new Servo##name_##Rule(rule.forget(), line, column); \
break; \
}
CASE_RULE(STYLE, Style)

View File

@ -13,7 +13,8 @@ using namespace mozilla::dom;
namespace mozilla {
ServoDocumentRule::ServoDocumentRule(RefPtr<RawServoDocumentRule> aRawRule)
ServoDocumentRule::ServoDocumentRule(RefPtr<RawServoDocumentRule> aRawRule,
uint32_t aLine, uint32_t aColumn)
: CSSMozDocumentRule(Servo_DocumentRule_GetRules(aRawRule).Consume())
, mRawRule(Move(aRawRule))
{

View File

@ -17,7 +17,8 @@ namespace mozilla {
class ServoDocumentRule final : public dom::CSSMozDocumentRule
{
public:
explicit ServoDocumentRule(RefPtr<RawServoDocumentRule> aRawRule);
ServoDocumentRule(RefPtr<RawServoDocumentRule> aRawRule,
uint32_t aLine, uint32_t aColumn);
NS_DECL_ISUPPORTS_INHERITED

View File

@ -15,7 +15,8 @@ using namespace mozilla::dom;
namespace mozilla {
ServoMediaRule::ServoMediaRule(RefPtr<RawServoMediaRule> aRawRule)
ServoMediaRule::ServoMediaRule(RefPtr<RawServoMediaRule> aRawRule,
uint32_t aLine, uint32_t aColumn)
: CSSMediaRule(Servo_MediaRule_GetRules(aRawRule).Consume())
, mRawRule(Move(aRawRule))
{

View File

@ -19,7 +19,8 @@ class ServoMediaList;
class ServoMediaRule final : public dom::CSSMediaRule
{
public:
explicit ServoMediaRule(RefPtr<RawServoMediaRule> aRawRule);
ServoMediaRule(RefPtr<RawServoMediaRule> aRawRule,
uint32_t aLine, uint32_t aColumn);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServoMediaRule, dom::CSSMediaRule)

View File

@ -15,8 +15,9 @@ namespace mozilla {
class ServoNamespaceRule : public dom::CSSNamespaceRule
{
public:
explicit ServoNamespaceRule(already_AddRefed<RawServoNamespaceRule> aRule)
: CSSNamespaceRule(0, 0)
ServoNamespaceRule(already_AddRefed<RawServoNamespaceRule> aRule,
uint32_t aLine, uint32_t aColumn)
: CSSNamespaceRule(aLine, aColumn)
, mRawRule(Move(aRule))
{
}

View File

@ -104,8 +104,9 @@ ServoPageRuleDeclaration::GetServoCSSParsingEnvironment() const
// -- ServoPageRule --------------------------------------------------
ServoPageRule::ServoPageRule(RefPtr<RawServoPageRule> aRawRule)
: CSSPageRule(0, 0)
ServoPageRule::ServoPageRule(RefPtr<RawServoPageRule> aRawRule,
uint32_t aLine, uint32_t aColumn)
: CSSPageRule(aLine, aColumn)
, mRawRule(Move(aRawRule))
, mDecls(Servo_PageRule_GetStyle(mRawRule).Consume())
{

View File

@ -51,7 +51,8 @@ private:
class ServoPageRule final : public dom::CSSPageRule
{
public:
explicit ServoPageRule(RefPtr<RawServoPageRule> aRawRule);
ServoPageRule(RefPtr<RawServoPageRule> aRawRule,
uint32_t aLine, uint32_t aColumn);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(

View File

@ -109,8 +109,9 @@ ServoStyleRuleDeclaration::GetServoCSSParsingEnvironment() const
// -- ServoStyleRule --------------------------------------------------
ServoStyleRule::ServoStyleRule(already_AddRefed<RawServoStyleRule> aRawRule)
: BindingStyleRule(0, 0)
ServoStyleRule::ServoStyleRule(already_AddRefed<RawServoStyleRule> aRawRule,
uint32_t aLine, uint32_t aColumn)
: BindingStyleRule(aLine, aColumn)
, mRawRule(aRawRule)
, mDecls(Servo_StyleRule_GetStyle(mRawRule).Consume())
{

View File

@ -53,7 +53,8 @@ class ServoStyleRule final : public BindingStyleRule
, public nsIDOMCSSStyleRule
{
public:
explicit ServoStyleRule(already_AddRefed<RawServoStyleRule> aRawRule);
ServoStyleRule(already_AddRefed<RawServoStyleRule> aRawRule,
uint32_t aLine, uint32_t aColumn);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ServoStyleRule,

View File

@ -110,13 +110,14 @@ ServoStyleSheet::ParseSheet(css::Loader* aLoader,
Inner()->mSheet =
Servo_StyleSheet_FromUTF8Bytes(
aLoader, this, &input, mParsingMode, media, extraData).Consume();
aLoader, this, &input, mParsingMode, media, extraData, aLineNumber
).Consume();
} else {
// TODO(emilio): Once we have proper inner cloning (which we don't right
// now) we should update the mediaList here too, though it's slightly
// tricky.
Servo_StyleSheet_ClearAndUpdate(Inner()->mSheet, aLoader,
this, &input, extraData);
this, &input, extraData, aLineNumber);
}
Inner()->mURLData = extraData.forget();

View File

@ -14,7 +14,8 @@ using namespace mozilla::dom;
namespace mozilla {
ServoSupportsRule::ServoSupportsRule(RefPtr<RawServoSupportsRule> aRawRule)
ServoSupportsRule::ServoSupportsRule(RefPtr<RawServoSupportsRule> aRawRule,
uint32_t aLine, uint32_t aColumn)
: CSSSupportsRule(Servo_SupportsRule_GetRules(aRawRule).Consume())
, mRawRule(Move(aRawRule))
{

View File

@ -17,7 +17,8 @@ namespace mozilla {
class ServoSupportsRule final : public dom::CSSSupportsRule
{
public:
explicit ServoSupportsRule(RefPtr<RawServoSupportsRule> aRawRule);
ServoSupportsRule(RefPtr<RawServoSupportsRule> aRawRule,
uint32_t aLine, uint32_t aColumn);
NS_DECL_ISUPPORTS_INHERITED

View File

@ -28,7 +28,7 @@ static void ServoParsingBench() {
NullPrincipalURI::Create(), nullptr, NullPrincipal::Create());
for (int i = 0; i < PARSING_REPETITIONS; i++) {
RefPtr<RawServoStyleSheet> stylesheet = Servo_StyleSheet_FromUTF8Bytes(
nullptr, nullptr, &css, eAuthorSheetFeatures, nullptr, data
nullptr, nullptr, &css, eAuthorSheetFeatures, nullptr, data, 0
).Consume();
}
}

View File

@ -70,7 +70,7 @@ to mochitest command.
* test_transitions.html: pseudo elements [12]
* Events:
* test_animations_event_order.html [2]
* test_computed_style.html `gradient`: -moz- and -webkit-prefixed gradient values [35]
* test_computed_style.html `gradient`: -moz- and -webkit-prefixed gradient values [22]
* test_bug829816.html: counter-{reset,increment} serialization difference bug 1363968 [8]
* \@counter-style support bug 1328319
* test_counter_descriptor_storage.html [1]
@ -121,8 +121,6 @@ to mochitest command.
* ... `-moz-radial-gradient` [309]
* ... `-moz-repeating-` [298]
* test_specified_value_serialization.html `-moz-linear-gradient` [2]
* -webkit-gradient() bug 1363986
* test_value_storage.html `-webkit-gradient` [225]
* serialization of prefixed gradient functions bug 1358710
* test_specified_value_serialization.html `-webkit-linear-gradient` [1]
* test_specified_value_serialization.html `-webkit-radial-gradient` [1]
@ -222,6 +220,8 @@ to mochitest command.
* Gecko clamps rather than rejects invalid unicode range bug 1355356
* test_font_face_parser.html `U+??????` [2]
* ... `12FFFF` [2]
* Gecko rejects calc() in -webkit-gradient bug 1363349
* test_property_syntax_errors.html `-webkit-gradient` [20]
* test_property_syntax_errors.html `linear-gradient(0,`: unitless zero as degree [10]
## Spec Unclear

View File

@ -1,18 +1,6 @@
# WeaveService has to restrict its registration for the app-startup category
# to the specific list of apps that use it so it doesn't get loaded in xpcshell.
# Thus we restrict it to these apps:
#
# b2g: {3c2e2abc-06d4-11e1-ac3b-374f68613e61}
# browser: {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
# mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110}
# mobile/xul: {a23983c0-fd0e-11dc-95ff-0800200c9a66}
# suite (comm): {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}
# graphene: {d1bfe7d9-c01e-4237-998b-7b5f960a4314}
# Weave.js
component {74b89fb0-f200-4ae8-a3ec-dd164117f6de} Weave.js
contract @mozilla.org/weave/service;1 {74b89fb0-f200-4ae8-a3ec-dd164117f6de}
category app-startup WeaveService service,@mozilla.org/weave/service;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66} application={92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} application={99bceaaa-e3c6-48c1-b981-ef9b46b67d60} application={d1bfe7d9-c01e-4237-998b-7b5f960a4314}
component {d28f8a0b-95da-48f4-b712-caf37097be41} Weave.js
contract @mozilla.org/network/protocol/about;1?what=sync-log {d28f8a0b-95da-48f4-b712-caf37097be41}

View File

@ -94,6 +94,32 @@ WeaveService.prototype = {
return onReadyPromise;
},
init() {
// Force Weave service to load if it hasn't triggered from overlays
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.timer.initWithCallback({
notify: () => {
let isConfigured = false;
// We only load more if it looks like Sync is configured.
if (this.enabled) {
// We have an associated FxAccount. So, do a more thorough check.
// This will import a number of modules and thus increase memory
// accordingly. We could potentially copy code performed by
// this check into this file if our above code is yielding too
// many false positives.
Components.utils.import("resource://services-sync/main.js");
isConfigured = Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED;
}
let getHistogramById = Services.telemetry.getHistogramById;
getHistogramById("WEAVE_CONFIGURED").add(isConfigured);
if (isConfigured) {
getHistogramById("WEAVE_CONFIGURED_MASTER_PASSWORD").add(Utils.mpEnabled());
this.ensureLoaded();
}
}
}, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
},
/**
* Whether Sync appears to be enabled.
*
@ -105,42 +131,6 @@ WeaveService.prototype = {
get enabled() {
let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH);
return prefs.prefHasUserValue("username");
},
observe(subject, topic, data) {
switch (topic) {
case "app-startup":
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
os.addObserver(this, "final-ui-startup", true);
break;
case "final-ui-startup":
// Force Weave service to load if it hasn't triggered from overlays
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.timer.initWithCallback({
notify: () => {
let isConfigured = false;
// We only load more if it looks like Sync is configured.
if (this.enabled) {
// We have an associated FxAccount. So, do a more thorough check.
// This will import a number of modules and thus increase memory
// accordingly. We could potentially copy code performed by
// this check into this file if our above code is yielding too
// many false positives.
Components.utils.import("resource://services-sync/main.js");
isConfigured = Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED;
}
let getHistogramById = Services.telemetry.getHistogramById;
getHistogramById("WEAVE_CONFIGURED").add(isConfigured);
if (isConfigured) {
getHistogramById("WEAVE_CONFIGURED_MASTER_PASSWORD").add(Utils.mpEnabled());
this.ensureLoaded();
}
}
}, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
break;
}
}
};

View File

@ -110,7 +110,6 @@ let SyncedTabsInternal = {
let engine = Weave.Service.engineManager.get("tabs");
let seenURLs = new Set();
let ntabs = 0;
for (let client of Object.values(engine.getAllClients())) {
@ -123,24 +122,14 @@ let SyncedTabsInternal = {
for (let tab of client.tabs) {
let url = tab.urlHistory[0];
log.debug("remote tab", url);
// Note there are some issues with tracking "seen" tabs, including:
// * We really can't return the entire urlHistory record as we are
// only checking the first entry - others might be different.
// * We don't update the |lastUsed| timestamp to reflect the
// most-recently-seen time.
// In a followup we should consider simply dropping this |seenUrls|
// check and return duplicate records - it seems the user will be more
// confused by tabs not showing up on a device (because it was detected
// as a dupe so it only appears on a different device) than being
// confused by seeing the same tab on different clients.
if (!url || seenURLs.has(url)) {
if (!url) {
continue;
}
let tabRepr = await this._makeTab(client, tab, url, showRemoteIcons);
if (filter && !this._tabMatchesFilter(tabRepr, filter)) {
continue;
}
seenURLs.add(url);
clientRepr.tabs.push(tabRepr);
}
// We return all clients, even those without tabs - the consumer should

View File

@ -217,3 +217,32 @@ add_task(async function test_filter() {
equal(clients[0].tabs.length, 1);
equal(clients[0].tabs[0].url, "http://foo.com/");
});
add_task(async function test_duplicatesTabsAcrossClients() {
await configureClients({
guid_desktop: {
clientName: "My Desktop",
tabs: [
{
urlHistory: ["http://foo.com/"],
title: "A test page.",
}],
},
guid_mobile: {
clientName: "My Phone",
tabs: [
{
urlHistory: ["http://foo.com/"],
title: "A test page.",
}],
},
});
let clients = await SyncedTabs.getTabClients();
equal(clients.length, 2);
equal(clients[0].tabs.length, 1);
equal(clients[1].tabs.length, 1);
equal(clients[0].tabs[0].url, "http://foo.com/");
equal(clients[1].tabs[0].url, "http://foo.com/");
});

3
servo/Cargo.lock generated
View File

@ -1024,6 +1024,7 @@ dependencies = [
name = "gfx_tests"
version = "0.0.1"
dependencies = [
"cssparser 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx 0.0.1",
"ipc-channel 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1",
@ -1674,7 +1675,7 @@ dependencies = [
[[package]]
name = "mozjs_sys"
version = "0.0.0"
source = "git+https://github.com/servo/mozjs#29132f6790dd0c066f10fc398a7071f6a5b6bc65"
source = "git+https://github.com/servo/mozjs#834ce35c3f008010213351107b68f397989d2ffd"
dependencies = [
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -57,12 +57,14 @@ use style::properties::{self, ServoComputedValues};
use style::properties::longhands::border_image_repeat::computed_value::RepeatKeyword;
use style::properties::style_structs;
use style::servo::restyle_damage::REPAINT;
use style::values::{Either, RGBA, computed};
use style::values::computed::{AngleOrCorner, Gradient, GradientItem, GradientKind, LengthOrPercentage};
use style::values::computed::{LengthOrPercentageOrAuto, LengthOrKeyword, LengthOrPercentageOrKeyword};
use style::values::computed::{NumberOrPercentage, Position};
use style::values::computed::image::{EndingShape, SizeKeyword};
use style::values::specified::{HorizontalDirection, VerticalDirection};
use style::values::{Either, RGBA};
use style::values::computed::{Gradient, GradientItem, LengthOrPercentage};
use style::values::computed::{LengthOrPercentageOrAuto, NumberOrPercentage, Position};
use style::values::computed::image::{EndingShape, LineDirection};
use style::values::generics::image::{Circle, Ellipse, EndingShape as GenericEndingShape};
use style::values::generics::image::{GradientItem as GenericGradientItem, GradientKind};
use style::values::generics::image::{Image, ShapeExtent};
use style::values::specified::position::{X, Y};
use style_traits::CSSPixel;
use style_traits::cursor::Cursor;
use table_cell::CollapsedBordersForCell;
@ -390,7 +392,7 @@ pub trait FragmentDisplayListBuilding {
fn convert_linear_gradient(&self,
bounds: &Rect<Au>,
stops: &[GradientItem],
angle_or_corner: &AngleOrCorner,
direction: &LineDirection,
repeating: bool,
style: &ServoComputedValues)
-> display_list::Gradient;
@ -610,7 +612,7 @@ fn convert_gradient_stops(gradient_items: &[GradientItem],
// Only keep the color stops, discard the color interpolation hints.
let mut stop_items = gradient_items.iter().filter_map(|item| {
match *item {
GradientItem::ColorStop(ref stop) => Some(*stop),
GenericGradientItem::ColorStop(ref stop) => Some(*stop),
_ => None,
}
}).collect::<Vec<_>>();
@ -758,36 +760,46 @@ fn get_ellipse_radius<F>(size: &Size2D<Au>, center: &Point2D<Au>, cmp: F) -> Siz
/// Determines the radius of a circle if it was not explictly provided.
/// https://drafts.csswg.org/css-images-3/#typedef-size
fn convert_circle_size_keyword(keyword: SizeKeyword,
fn convert_circle_size_keyword(keyword: ShapeExtent,
size: &Size2D<Au>,
center: &Point2D<Au>) -> Size2D<Au> {
use style::values::computed::image::SizeKeyword::*;
let radius = match keyword {
ClosestSide | Contain => {
ShapeExtent::ClosestSide | ShapeExtent::Contain => {
let dist = get_distance_to_sides(size, center, ::std::cmp::min);
::std::cmp::min(dist.width, dist.height)
}
FarthestSide => {
ShapeExtent::FarthestSide => {
let dist = get_distance_to_sides(size, center, ::std::cmp::max);
::std::cmp::max(dist.width, dist.height)
}
ClosestCorner => get_distance_to_corner(size, center, ::std::cmp::min),
FarthestCorner | Cover => get_distance_to_corner(size, center, ::std::cmp::max),
ShapeExtent::ClosestCorner => {
get_distance_to_corner(size, center, ::std::cmp::min)
},
ShapeExtent::FarthestCorner | ShapeExtent::Cover => {
get_distance_to_corner(size, center, ::std::cmp::max)
},
};
Size2D::new(radius, radius)
}
/// Determines the radius of an ellipse if it was not explictly provided.
/// https://drafts.csswg.org/css-images-3/#typedef-size
fn convert_ellipse_size_keyword(keyword: SizeKeyword,
fn convert_ellipse_size_keyword(keyword: ShapeExtent,
size: &Size2D<Au>,
center: &Point2D<Au>) -> Size2D<Au> {
use style::values::computed::image::SizeKeyword::*;
match keyword {
ClosestSide | Contain => get_distance_to_sides(size, center, ::std::cmp::min),
FarthestSide => get_distance_to_sides(size, center, ::std::cmp::max),
ClosestCorner => get_ellipse_radius(size, center, ::std::cmp::min),
FarthestCorner | Cover => get_ellipse_radius(size, center, ::std::cmp::max),
ShapeExtent::ClosestSide | ShapeExtent::Contain => {
get_distance_to_sides(size, center, ::std::cmp::min)
},
ShapeExtent::FarthestSide => {
get_distance_to_sides(size, center, ::std::cmp::max)
},
ShapeExtent::ClosestCorner => {
get_ellipse_radius(size, center, ::std::cmp::min)
},
ShapeExtent::FarthestCorner | ShapeExtent::Cover => {
get_ellipse_radius(size, center, ::std::cmp::max)
},
}
}
@ -853,9 +865,9 @@ impl FragmentDisplayListBuilding for Fragment {
// http://www.w3.org/TR/CSS21/colors.html#background
let background = style.get_background();
for (i, background_image) in background.background_image.0.iter().enumerate().rev() {
match background_image.0 {
None => {}
Some(computed::Image::Gradient(ref gradient)) => {
match *background_image {
Either::First(_) => {}
Either::Second(Image::Gradient(ref gradient)) => {
self.build_display_list_for_background_gradient(state,
display_list_section,
&absolute_bounds,
@ -864,7 +876,7 @@ impl FragmentDisplayListBuilding for Fragment {
gradient,
style);
}
Some(computed::Image::Url(ref image_url)) => {
Either::Second(Image::Url(ref image_url)) => {
if let Some(url) = image_url.url() {
self.build_display_list_for_background_image(state,
style,
@ -875,10 +887,10 @@ impl FragmentDisplayListBuilding for Fragment {
i);
}
}
Some(computed::Image::ImageRect(_)) => {
Either::Second(Image::Rect(_)) => {
// TODO: Implement `-moz-image-rect`
}
Some(computed::Image::Element(_)) => {
Either::Second(Image::Element(_)) => {
// TODO: Implement `-moz-element`
}
}
@ -1097,26 +1109,26 @@ impl FragmentDisplayListBuilding for Fragment {
fn convert_linear_gradient(&self,
bounds: &Rect<Au>,
stops: &[GradientItem],
angle_or_corner: &AngleOrCorner,
direction: &LineDirection,
repeating: bool,
style: &ServoComputedValues)
-> display_list::Gradient {
let angle = match *angle_or_corner {
AngleOrCorner::Angle(angle) => angle.radians(),
AngleOrCorner::Corner(horizontal, vertical) => {
let angle = match *direction {
LineDirection::Angle(angle) => angle.radians(),
LineDirection::Corner(horizontal, vertical) => {
// This the angle for one of the diagonals of the box. Our angle
// will either be this one, this one + PI, or one of the other
// two perpendicular angles.
let atan = (bounds.size.height.to_f32_px() /
bounds.size.width.to_f32_px()).atan();
match (horizontal, vertical) {
(HorizontalDirection::Right, VerticalDirection::Bottom)
(X::Right, Y::Bottom)
=> f32::consts::PI - atan,
(HorizontalDirection::Left, VerticalDirection::Bottom)
(X::Left, Y::Bottom)
=> f32::consts::PI + atan,
(HorizontalDirection::Right, VerticalDirection::Top)
(X::Right, Y::Top)
=> atan,
(HorizontalDirection::Left, VerticalDirection::Top)
(X::Left, Y::Top)
=> -atan,
}
}
@ -1170,16 +1182,18 @@ impl FragmentDisplayListBuilding for Fragment {
let center = Point2D::new(specified(center.horizontal, bounds.size.width),
specified(center.vertical, bounds.size.height));
let radius = match *shape {
EndingShape::Circle(LengthOrKeyword::Length(length))
=> Size2D::new(length, length),
EndingShape::Circle(LengthOrKeyword::Keyword(word))
=> convert_circle_size_keyword(word, &bounds.size, &center),
EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(horizontal,
vertical))
=> Size2D::new(specified(horizontal, bounds.size.width),
specified(vertical, bounds.size.height)),
EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(word))
=> convert_ellipse_size_keyword(word, &bounds.size, &center),
GenericEndingShape::Circle(Circle::Radius(length)) => {
Size2D::new(length, length)
},
GenericEndingShape::Circle(Circle::Extent(extent)) => {
convert_circle_size_keyword(extent, &bounds.size, &center)
},
GenericEndingShape::Ellipse(Ellipse::Radii(x, y)) => {
Size2D::new(specified(x, bounds.size.width), specified(y, bounds.size.height))
},
GenericEndingShape::Ellipse(Ellipse::Extent(extent)) => {
convert_ellipse_size_keyword(extent, &bounds.size, &center)
},
};
let mut stops = convert_gradient_stops(stops, radius.width, style);
@ -1221,7 +1235,7 @@ impl FragmentDisplayListBuilding for Fragment {
style.get_cursor(Cursor::Default),
display_list_section);
let display_item = match gradient.gradient_kind {
let display_item = match gradient.kind {
GradientKind::Linear(ref angle_or_corner) => {
let gradient = self.convert_linear_gradient(&bounds,
&gradient.items[..],
@ -1342,8 +1356,8 @@ impl FragmentDisplayListBuilding for Fragment {
style.get_cursor(Cursor::Default),
display_list_section);
match border_style_struct.border_image_source.0 {
None => {
match border_style_struct.border_image_source {
Either::First(_) => {
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
base: base,
border_widths: border.to_physical(style.writing_mode),
@ -1357,8 +1371,8 @@ impl FragmentDisplayListBuilding for Fragment {
}),
}));
}
Some(computed::Image::Gradient(ref gradient)) => {
match gradient.gradient_kind {
Either::Second(Image::Gradient(ref gradient)) => {
match gradient.kind {
GradientKind::Linear(angle_or_corner) => {
let grad = self.convert_linear_gradient(&bounds,
&gradient.items[..],
@ -1398,13 +1412,13 @@ impl FragmentDisplayListBuilding for Fragment {
}
}
}
Some(computed::Image::ImageRect(..)) => {
Either::Second(Image::Rect(..)) => {
// TODO: Handle border-image with `-moz-image-rect`.
}
Some(computed::Image::Element(..)) => {
Either::Second(Image::Element(..)) => {
// TODO: Handle border-image with `-moz-element`.
}
Some(computed::Image::Url(ref image_url)) => {
Either::Second(Image::Url(ref image_url)) => {
if let Some(url) = image_url.url() {
let webrender_image = state.layout_context
.get_webrender_image_for_url(self.node,

View File

@ -559,10 +559,10 @@ pub fn should_be_blocked_due_to_nosniff(request_type: Type, response_headers: &H
mime!(Text / ("x-javascript")),
];
javascript_mime_types.contains(mime_type)
javascript_mime_types.iter()
.any(|mime| mime.0 == mime_type.0 && mime.1 == mime_type.1)
}
let text_css: Mime = mime!(Text / Css);
// Assumes str::starts_with is equivalent to mime::TopLevel
return match request_type {
// Step 6
@ -575,8 +575,8 @@ pub fn should_be_blocked_due_to_nosniff(request_type: Type, response_headers: &H
// Step 7
Type::Style => {
match content_type_header {
Some(&ContentType(ref mime_type)) => mime_type != &text_css,
None => true
Some(&ContentType(Mime(TopLevel::Text, SubLevel::Css, _))) => false,
_ => true
}
}
// Step 8

View File

@ -109,7 +109,7 @@ use style::sink::Push;
use style::stylearc::Arc;
use style::stylist::ApplicableDeclarationBlock;
use style::thread_state;
use style::values::CSSFloat;
use style::values::{CSSFloat, Either};
use style::values::specified::{self, CSSColor};
use stylesheet_loader::StylesheetOwner;
@ -427,9 +427,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
shared_lock,
PropertyDeclaration::BackgroundImage(
background_image::SpecifiedValue(vec![
background_image::single_value::SpecifiedValue(Some(
specified::Image::for_cascade(url.into())
))
Either::Second(specified::Image::for_cascade(url.into()))
]))));
}

View File

@ -88,6 +88,7 @@ impl Stylesheet {
&string,
url_data,
stylesheet_loader,
error_reporter)
error_reporter,
0)
}
}

View File

@ -12,6 +12,7 @@
use computed_values::{font_style, font_weight, font_stretch};
use computed_values::font_family::FamilyName;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use cssparser::SourceLocation;
#[cfg(feature = "gecko")] use gecko_bindings::structs::CSSFontFaceDescriptors;
#[cfg(feature = "gecko")] use cssparser::UnicodeRange;
use parser::{ParserContext, log_css_error, Parse};
@ -74,8 +75,10 @@ impl ToCss for UrlSource {
/// Parse the block inside a `@font-face` rule.
///
/// Note that the prelude parsing code lives in the `stylesheets` module.
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser) -> FontFaceRuleData {
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser, location: SourceLocation)
-> FontFaceRuleData {
let mut rule = FontFaceRuleData::empty();
rule.source_location = location;
{
let parser = FontFaceRuleParser {
context: context,
@ -186,6 +189,8 @@ macro_rules! font_face_descriptors_common {
#[$doc]
pub $ident: Option<$ty>,
)*
/// Line and column of the @font-face rule source code.
pub source_location: SourceLocation,
}
impl FontFaceRuleData {
@ -194,6 +199,10 @@ macro_rules! font_face_descriptors_common {
$(
$ident: None,
)*
source_location: SourceLocation {
line: 0,
column: 0,
},
}
}

View File

@ -16,8 +16,9 @@ use gecko_bindings::structs::{nsCSSUnit, nsStyleCoord_CalcValue, nsStyleImage};
use gecko_bindings::structs::{nsresult, SheetType};
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
use stylesheets::{Origin, RulesMutateError};
use values::computed::{Angle, CalcLengthOrPercentage, Gradient, GradientItem, Image};
use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
use values::generics::image::{CompatMode, Image as GenericImage, GradientItem};
impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
@ -138,10 +139,10 @@ impl nsStyleImage {
/// Set a given Servo `Image` value into this `nsStyleImage`.
pub fn set(&mut self, image: Image, cacheable: &mut bool) {
match image {
Image::Gradient(gradient) => {
GenericImage::Gradient(gradient) => {
self.set_gradient(gradient)
},
Image::Url(ref url) => {
GenericImage::Url(ref url) => {
unsafe {
Gecko_SetUrlImageValue(self, url.for_ffi());
// We unfortunately must make any url() value uncacheable, since
@ -154,7 +155,7 @@ impl nsStyleImage {
*cacheable = false;
}
},
Image::ImageRect(ref image_rect) => {
GenericImage::Rect(ref image_rect) => {
unsafe {
Gecko_SetUrlImageValue(self, image_rect.url.for_ffi());
Gecko_InitializeImageCropRect(self);
@ -176,7 +177,7 @@ impl nsStyleImage {
image_rect.left.to_gecko_style_coord(&mut rect.data_at_mut(3));
}
}
Image::Element(ref element) => {
GenericImage::Element(ref element) => {
unsafe {
Gecko_SetImageElement(self, element.as_ptr());
}
@ -191,9 +192,9 @@ impl nsStyleImage {
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE};
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE};
use gecko_bindings::structs::nsStyleCoord;
use values::computed::{AngleOrCorner, GradientKind, GradientShape, LengthOrKeyword};
use values::computed::LengthOrPercentageOrKeyword;
use values::specified::{HorizontalDirection, SizeKeyword, VerticalDirection};
use values::computed::image::LineDirection;
use values::generics::image::{Circle, Ellipse, EndingShape, GradientKind, ShapeExtent};
use values::specified::position::{X, Y};
let stop_count = gradient.items.len();
if stop_count >= ::std::u32::MAX as usize {
@ -201,32 +202,32 @@ impl nsStyleImage {
return;
}
let gecko_gradient = match gradient.gradient_kind {
GradientKind::Linear(angle_or_corner) => {
let gecko_gradient = match gradient.kind {
GradientKind::Linear(direction) => {
let gecko_gradient = unsafe {
Gecko_CreateGradient(NS_STYLE_GRADIENT_SHAPE_LINEAR as u8,
NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8,
gradient.repeating,
/* legacy_syntax = */ false,
gradient.compat_mode == CompatMode::WebKit,
stop_count as u32)
};
match angle_or_corner {
AngleOrCorner::Angle(angle) => {
match direction {
LineDirection::Angle(angle) => {
unsafe {
(*gecko_gradient).mAngle.set(angle);
(*gecko_gradient).mBgPosX.set_value(CoordDataValue::None);
(*gecko_gradient).mBgPosY.set_value(CoordDataValue::None);
}
},
AngleOrCorner::Corner(horiz, vert) => {
LineDirection::Corner(horiz, vert) => {
let percent_x = match horiz {
HorizontalDirection::Left => 0.0,
HorizontalDirection::Right => 1.0,
X::Left => 0.0,
X::Right => 1.0,
};
let percent_y = match vert {
VerticalDirection::Top => 0.0,
VerticalDirection::Bottom => 1.0,
Y::Top => 0.0,
Y::Bottom => 1.0,
};
unsafe {
@ -243,28 +244,28 @@ impl nsStyleImage {
GradientKind::Radial(shape, position) => {
let keyword_to_gecko_size = |keyword| {
match keyword {
SizeKeyword::ClosestSide => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE,
SizeKeyword::FarthestSide => NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE,
SizeKeyword::ClosestCorner => NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER,
SizeKeyword::FarthestCorner => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER,
SizeKeyword::Contain => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE,
SizeKeyword::Cover => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER,
ShapeExtent::ClosestSide => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE,
ShapeExtent::FarthestSide => NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE,
ShapeExtent::ClosestCorner => NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER,
ShapeExtent::FarthestCorner => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER,
ShapeExtent::Contain => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE,
ShapeExtent::Cover => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER,
}
};
let (gecko_shape, gecko_size) = match shape {
GradientShape::Circle(ref length) => {
let size = match *length {
LengthOrKeyword::Keyword(keyword) => {
keyword_to_gecko_size(keyword)
EndingShape::Circle(ref circle) => {
let size = match *circle {
Circle::Extent(extent) => {
keyword_to_gecko_size(extent)
},
_ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
};
(NS_STYLE_GRADIENT_SHAPE_CIRCULAR as u8, size as u8)
},
GradientShape::Ellipse(ref length) => {
let size = match *length {
LengthOrPercentageOrKeyword::Keyword(keyword) => {
keyword_to_gecko_size(keyword)
EndingShape::Ellipse(ref ellipse) => {
let size = match *ellipse {
Ellipse::Extent(extent) => {
keyword_to_gecko_size(extent)
},
_ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
};
@ -276,7 +277,7 @@ impl nsStyleImage {
Gecko_CreateGradient(gecko_shape,
gecko_size,
gradient.repeating,
/* legacy_syntax = */ false,
gradient.compat_mode == CompatMode::WebKit,
stop_count as u32)
};
@ -289,22 +290,19 @@ impl nsStyleImage {
// Setting radius values depending shape
match shape {
GradientShape::Circle(length) => {
if let LengthOrKeyword::Length(len) = length {
unsafe {
(*gecko_gradient).mRadiusX.set_value(CoordDataValue::Coord(len.0));
(*gecko_gradient).mRadiusY.set_value(CoordDataValue::Coord(len.0));
}
EndingShape::Circle(Circle::Radius(length)) => {
unsafe {
(*gecko_gradient).mRadiusX.set_value(CoordDataValue::Coord(length.0));
(*gecko_gradient).mRadiusY.set_value(CoordDataValue::Coord(length.0));
}
},
GradientShape::Ellipse(length) => {
if let LengthOrPercentageOrKeyword::LengthOrPercentage(first_len, second_len) = length {
unsafe {
(*gecko_gradient).mRadiusX.set(first_len);
(*gecko_gradient).mRadiusY.set(second_len);
}
EndingShape::Ellipse(Ellipse::Radii(x, y)) => {
unsafe {
(*gecko_gradient).mRadiusX.set(x);
(*gecko_gradient).mRadiusY.set(y);
}
},
_ => {},
}
unsafe {
(*gecko_gradient).mBgPosX.set(position.horizontal);

View File

@ -1255,7 +1255,8 @@ extern "C" {
-> *const ::std::os::raw::c_char;
}
extern "C" {
pub fn Gecko_CSSFontFaceRule_Create() -> *mut nsCSSFontFaceRule;
pub fn Gecko_CSSFontFaceRule_Create(line: u32, column: u32)
-> *mut nsCSSFontFaceRule;
}
extern "C" {
pub fn Gecko_CSSFontFaceRule_GetCssText(rule: *const nsCSSFontFaceRule,
@ -1621,7 +1622,8 @@ extern "C" {
media_list:
*const RawServoMediaList,
extra_data:
*mut RawGeckoURLExtraData)
*mut RawGeckoURLExtraData,
line_number_offset: u32)
-> RawServoStyleSheetStrong;
}
extern "C" {
@ -1636,7 +1638,8 @@ extern "C" {
*mut ServoStyleSheet,
data: *const nsACString,
extra_data:
*mut RawGeckoURLExtraData);
*mut RawGeckoURLExtraData,
line_number_offset: u32);
}
extern "C" {
pub fn Servo_StyleSheet_HasRules(sheet: RawServoStyleSheetBorrowed)
@ -1726,7 +1729,8 @@ extern "C" {
}
extern "C" {
pub fn Servo_CssRules_GetStyleRuleAt(rules: ServoCssRulesBorrowed,
index: u32)
index: u32, line: *mut u32,
column: *mut u32)
-> RawServoStyleRuleStrong;
}
extern "C" {
@ -1739,7 +1743,8 @@ extern "C" {
}
extern "C" {
pub fn Servo_CssRules_GetMediaRuleAt(rules: ServoCssRulesBorrowed,
index: u32)
index: u32, line: *mut u32,
column: *mut u32)
-> RawServoMediaRuleStrong;
}
extern "C" {
@ -1756,7 +1761,8 @@ extern "C" {
}
extern "C" {
pub fn Servo_CssRules_GetNamespaceRuleAt(rules: ServoCssRulesBorrowed,
index: u32)
index: u32, line: *mut u32,
column: *mut u32)
-> RawServoNamespaceRuleStrong;
}
extern "C" {
@ -1769,7 +1775,9 @@ extern "C" {
}
extern "C" {
pub fn Servo_CssRules_GetPageRuleAt(rules: ServoCssRulesBorrowed,
index: u32) -> RawServoPageRuleStrong;
index: u32, line: *mut u32,
column: *mut u32)
-> RawServoPageRuleStrong;
}
extern "C" {
pub fn Servo_PageRule_Debug(rule: RawServoPageRuleBorrowed,
@ -1781,7 +1789,8 @@ extern "C" {
}
extern "C" {
pub fn Servo_CssRules_GetSupportsRuleAt(rules: ServoCssRulesBorrowed,
index: u32)
index: u32, line: *mut u32,
column: *mut u32)
-> RawServoSupportsRuleStrong;
}
extern "C" {
@ -1798,7 +1807,8 @@ extern "C" {
}
extern "C" {
pub fn Servo_CssRules_GetDocumentRuleAt(rules: ServoCssRulesBorrowed,
index: u32)
index: u32, line: *mut u32,
column: *mut u32)
-> RawServoDocumentRuleStrong;
}
extern "C" {

View File

@ -117,7 +117,9 @@ impl ToNsCssValue for Vec<UnicodeRange> {
impl From<FontFaceRuleData> for FontFaceRule {
fn from(data: FontFaceRuleData) -> FontFaceRule {
let mut result = unsafe {
UniqueRefPtr::from_addrefed(bindings::Gecko_CSSFontFaceRule_Create())
UniqueRefPtr::from_addrefed(bindings::Gecko_CSSFontFaceRule_Create(
data.source_location.line as u32, data.source_location.column as u32
))
};
data.set_descriptors(&mut result.mDecl.mDescriptors);
result.get()

View File

@ -927,7 +927,7 @@ fn static_assert() {
Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource);
}
if let Some(image) = image.0 {
if let Either::Second(image) = image {
self.gecko.mBorderImageSource.set(image, &mut false)
}
}
@ -2879,7 +2879,7 @@ fn static_assert() {
for (image, geckoimage) in images.zip(self.gecko.${image_layers_field}
.mLayers.iter_mut()) {
if let Some(image) = image.0 {
if let Either::Second(image) = image {
geckoimage.mImage.set(image, cacheable)
}
}

View File

@ -12,9 +12,9 @@ ${helpers.predefined_type("background-color", "CSSColor",
spec="https://drafts.csswg.org/css-backgrounds/#background-color",
animation_value_type="IntermediateColor", complex_color=True)}
${helpers.predefined_type("background-image", "LayerImage",
initial_value="computed_value::T(None)",
initial_specified_value="SpecifiedValue(None)",
${helpers.predefined_type("background-image", "ImageLayer",
initial_value="Either::First(None_)",
initial_specified_value="Either::First(None_)",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
vector="True",
animation_value_type="none",

View File

@ -190,9 +190,9 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
animation_value_type="none")}
${helpers.predefined_type("border-image-source", "LayerImage",
initial_value="computed_value::T(None)",
initial_specified_value="SpecifiedValue(None)",
${helpers.predefined_type("border-image-source", "ImageLayer",
initial_value="Either::First(None_)",
initial_specified_value="Either::First(None_)",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
vector=False,
animation_value_type="none",
@ -717,7 +717,7 @@ ${helpers.predefined_type("border-image-source", "LayerImage",
let mut values = vec![];
for _ in 0..4 {
let value = input.try(|input| NumberOrPercentage::parse(context, input));
let value = input.try(|input| NumberOrPercentage::parse_non_negative(context, input));
match value {
Ok(val) => values.push(val),
Err(_) => break,

View File

@ -141,9 +141,10 @@ ${helpers.single_keyword("mask-composite",
extra_prefixes="webkit",
animation_value_type="none",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")}
${helpers.predefined_type("mask-image", "LayerImage",
initial_value="computed_value::T(None)",
initial_specified_value="SpecifiedValue(None)",
${helpers.predefined_type("mask-image", "ImageLayer",
initial_value="Either::First(None_)",
initial_specified_value="Either::First(None_)",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image",
vector=True,
products="gecko",

View File

@ -10,7 +10,7 @@ use {Atom, Prefix, Namespace};
use context::QuirksMode;
use counter_style::{CounterStyleRule, parse_counter_style_name, parse_counter_style_body};
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser};
use cssparser::{AtRuleType, RuleListParser, parse_one_rule};
use cssparser::{AtRuleType, RuleListParser, parse_one_rule, SourceLocation};
use cssparser::ToCss as ParserToCss;
use document_condition::DocumentCondition;
use error_reporting::{ParseErrorReporter, NullReporter};
@ -489,12 +489,22 @@ impl ToCssWithGuard for CssRule {
}
}
/// Calculates the location of a rule's source given an offset.
fn get_location_with_offset(location: SourceLocation, offset: u64)
-> SourceLocation {
SourceLocation {
line: location.line + offset as usize - 1,
column: location.column,
}
}
#[derive(Debug, PartialEq)]
#[allow(missing_docs)]
pub struct NamespaceRule {
/// `None` for the default Namespace
pub prefix: Option<Prefix>,
pub url: Namespace,
pub source_location: SourceLocation,
}
impl ToCssWithGuard for NamespaceRule {
@ -581,6 +591,7 @@ impl ToCssWithGuard for KeyframesRule {
pub struct MediaRule {
pub media_queries: Arc<Locked<MediaList>>,
pub rules: Arc<Locked<CssRules>>,
pub source_location: SourceLocation,
}
impl ToCssWithGuard for MediaRule {
@ -609,6 +620,8 @@ pub struct SupportsRule {
pub rules: Arc<Locked<CssRules>>,
/// The result of evaluating the condition
pub enabled: bool,
/// The line and column of the rule's source code.
pub source_location: SourceLocation,
}
impl ToCssWithGuard for SupportsRule {
@ -630,15 +643,19 @@ impl ToCssWithGuard for SupportsRule {
///
/// [page]: https://drafts.csswg.org/css2/page.html#page-box
/// [page-selectors]: https://drafts.csswg.org/css2/page.html#page-selectors
#[allow(missing_docs)]
#[derive(Debug)]
pub struct PageRule(pub Arc<Locked<PropertyDeclarationBlock>>);
pub struct PageRule {
pub block: Arc<Locked<PropertyDeclarationBlock>>,
pub source_location: SourceLocation,
}
impl ToCssWithGuard for PageRule {
// Serialization of PageRule is not specced, adapted from steps for StyleRule.
fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
dest.write_str("@page { ")?;
let declaration_block = self.0.read_with(guard);
let declaration_block = self.block.read_with(guard);
declaration_block.to_css(dest)?;
if declaration_block.declarations().len() > 0 {
write!(dest, " ")?;
@ -652,6 +669,7 @@ impl ToCssWithGuard for PageRule {
pub struct StyleRule {
pub selectors: SelectorList<SelectorImpl>,
pub block: Arc<Locked<PropertyDeclarationBlock>>,
pub source_location: SourceLocation,
}
impl ToCssWithGuard for StyleRule {
@ -686,6 +704,8 @@ pub struct DocumentRule {
pub condition: DocumentCondition,
/// Child rules
pub rules: Arc<Locked<CssRules>>,
/// The line and column of the rule's source code.
pub source_location: SourceLocation,
}
impl ToCssWithGuard for DocumentRule {
@ -708,15 +728,15 @@ impl Stylesheet {
css: &str,
url_data: &UrlExtraData,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter) {
error_reporter: &ParseErrorReporter,
line_number_offset: u64) {
let mut namespaces = Namespaces::default();
// FIXME: we really should update existing.url_data with the given url_data,
// otherwise newly inserted rule may not have the right base url.
let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules(
css, url_data, existing.origin, &mut namespaces,
&existing.shared_lock, stylesheet_loader, error_reporter,
existing.quirks_mode, 0u64);
existing.quirks_mode, line_number_offset);
*existing.namespaces.write() = namespaces;
existing.dirty_on_viewport_size_change
.store(dirty_on_viewport_size_change, Ordering::Release);
@ -996,21 +1016,21 @@ pub enum VendorPrefix {
enum AtRulePrelude {
/// A @font-face rule prelude.
FontFace,
FontFace(SourceLocation),
/// A @counter-style rule prelude, with its counter style name.
CounterStyle(CustomIdent),
/// A @media rule prelude, with its media queries.
Media(Arc<Locked<MediaList>>),
Media(Arc<Locked<MediaList>>, SourceLocation),
/// An @supports rule, with its conditional
Supports(SupportsCondition),
Supports(SupportsCondition, SourceLocation),
/// A @viewport rule prelude.
Viewport,
/// A @keyframes rule, with its animation name and vendor prefix if exists.
Keyframes(KeyframesName, Option<VendorPrefix>),
/// A @page rule prelude.
Page,
Page(SourceLocation),
/// A @document rule, with its conditional.
Document(DocumentCondition),
Document(DocumentCondition, SourceLocation),
}
@ -1066,6 +1086,9 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
if self.state.get() <= State::Namespaces {
self.state.set(State::Namespaces);
let location = get_location_with_offset(input.current_source_location(),
self.context.line_number_offset);
let prefix_result = input.try(|input| input.expect_ident());
let url = Namespace::from(try!(input.expect_url_or_string()));
@ -1082,6 +1105,7 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
self.shared_lock.wrap(NamespaceRule {
prefix: opt_prefix,
url: url,
source_location: location,
})
))))
} else {
@ -1176,18 +1200,20 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
fn parse_prelude(&mut self, name: &str, input: &mut Parser)
-> Result<AtRuleType<AtRulePrelude, CssRule>, ()> {
let location = get_location_with_offset(input.current_source_location(),
self.context.line_number_offset);
match_ignore_ascii_case! { name,
"media" => {
let media_queries = parse_media_query_list(self.context, input);
let arc = Arc::new(self.shared_lock.wrap(media_queries));
Ok(AtRuleType::WithBlock(AtRulePrelude::Media(arc)))
Ok(AtRuleType::WithBlock(AtRulePrelude::Media(arc, location)))
},
"supports" => {
let cond = SupportsCondition::parse(input)?;
Ok(AtRuleType::WithBlock(AtRulePrelude::Supports(cond)))
Ok(AtRuleType::WithBlock(AtRulePrelude::Supports(cond, location)))
},
"font-face" => {
Ok(AtRuleType::WithBlock(AtRulePrelude::FontFace))
Ok(AtRuleType::WithBlock(AtRulePrelude::FontFace(location)))
},
"counter-style" => {
if !cfg!(feature = "gecko") {
@ -1229,7 +1255,7 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
},
"page" => {
if cfg!(feature = "gecko") {
Ok(AtRuleType::WithBlock(AtRulePrelude::Page))
Ok(AtRuleType::WithBlock(AtRulePrelude::Page(location)))
} else {
Err(())
}
@ -1237,7 +1263,7 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
"-moz-document" => {
if cfg!(feature = "gecko") {
let cond = DocumentCondition::parse(self.context, input)?;
Ok(AtRuleType::WithBlock(AtRulePrelude::Document(cond)))
Ok(AtRuleType::WithBlock(AtRulePrelude::Document(cond, location)))
} else {
Err(())
}
@ -1248,28 +1274,30 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CssRule, ()> {
match prelude {
AtRulePrelude::FontFace => {
AtRulePrelude::FontFace(location) => {
let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::FontFace));
Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap(
parse_font_face_block(&context, input).into()))))
parse_font_face_block(&context, input, location).into()))))
}
AtRulePrelude::CounterStyle(name) => {
let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::CounterStyle));
Ok(CssRule::CounterStyle(Arc::new(self.shared_lock.wrap(
parse_counter_style_body(name, &context, input)?))))
}
AtRulePrelude::Media(media_queries) => {
AtRulePrelude::Media(media_queries, location) => {
Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule {
media_queries: media_queries,
rules: self.parse_nested_rules(input, CssRuleType::Media),
source_location: location,
}))))
}
AtRulePrelude::Supports(cond) => {
AtRulePrelude::Supports(cond, location) => {
let enabled = cond.eval(self.context);
Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap(SupportsRule {
condition: cond,
rules: self.parse_nested_rules(input, CssRuleType::Supports),
enabled: enabled,
source_location: location,
}))))
}
AtRulePrelude::Viewport => {
@ -1285,18 +1313,20 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
vendor_prefix: prefix,
}))))
}
AtRulePrelude::Page => {
AtRulePrelude::Page(location) => {
let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::Page));
let declarations = parse_property_declaration_list(&context, input);
Ok(CssRule::Page(Arc::new(self.shared_lock.wrap(PageRule(
Arc::new(self.shared_lock.wrap(declarations))
)))))
Ok(CssRule::Page(Arc::new(self.shared_lock.wrap(PageRule {
block: Arc::new(self.shared_lock.wrap(declarations)),
source_location: location,
}))))
}
AtRulePrelude::Document(cond) => {
AtRulePrelude::Document(cond, location) => {
if cfg!(feature = "gecko") {
Ok(CssRule::Document(Arc::new(self.shared_lock.wrap(DocumentRule {
condition: cond,
rules: self.parse_nested_rules(input, CssRuleType::Document),
source_location: location,
}))))
} else {
unreachable!()
@ -1320,11 +1350,14 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
fn parse_block(&mut self, prelude: SelectorList<SelectorImpl>, input: &mut Parser)
-> Result<CssRule, ()> {
let location = get_location_with_offset(input.current_source_location(),
self.context.line_number_offset);
let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::Style));
let declarations = parse_property_declaration_list(&context, input);
Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule {
selectors: prelude,
block: Arc::new(self.shared_lock.wrap(declarations))
block: Arc::new(self.shared_lock.wrap(declarations)),
source_location: location,
}))))
}
}

View File

@ -7,687 +7,126 @@
//!
//! [image]: https://drafts.csswg.org/css-images/#image-values
use Atom;
use cssparser::{Color as CSSColor, serialize_identifier};
use cssparser::Color as CSSColor;
use std::f32::consts::PI;
use std::fmt;
use style_traits::ToCss;
use values::{Either, None_};
use values::computed::{Angle, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
use values::computed::position::Position;
use values::specified::{self, HorizontalDirection, VerticalDirection};
use values::specified::image::CompatMode;
use values::specified::url::SpecifiedUrl;
use values::generics::image::{CompatMode, ColorStop as GenericColorStop, EndingShape as GenericEndingShape};
use values::generics::image::{Gradient as GenericGradient, GradientItem as GenericGradientItem};
use values::generics::image::{Image as GenericImage, GradientKind as GenericGradientKind};
use values::generics::image::{ImageRect as GenericImageRect, LineDirection as GenericLineDirection};
use values::specified::image::LineDirection as SpecifiedLineDirection;
use values::specified::position::{X, Y};
pub use values::specified::SizeKeyword;
impl ToComputedValue for specified::Image {
type ComputedValue = Image;
#[inline]
fn to_computed_value(&self, context: &Context) -> Image {
match *self {
specified::Image::Url(ref url_value) => {
Image::Url(url_value.clone())
},
specified::Image::Gradient(ref gradient) => {
Image::Gradient(gradient.to_computed_value(context))
},
specified::Image::ImageRect(ref image_rect) => {
Image::ImageRect(image_rect.to_computed_value(context))
},
specified::Image::Element(ref selector) => {
Image::Element(selector.clone())
}
}
}
#[inline]
fn from_computed_value(computed: &Image) -> Self {
match *computed {
Image::Url(ref url_value) => {
specified::Image::Url(url_value.clone())
},
Image::Gradient(ref linear_gradient) => {
specified::Image::Gradient(
ToComputedValue::from_computed_value(linear_gradient)
)
},
Image::ImageRect(ref image_rect) => {
specified::Image::ImageRect(
ToComputedValue::from_computed_value(image_rect)
)
},
Image::Element(ref selector) => {
specified::Image::Element(selector.clone())
},
}
}
}
/// A computed image layer.
pub type ImageLayer = Either<None_, Image>;
/// Computed values for an image according to CSS-IMAGES.
/// https://drafts.csswg.org/css-images/#image-values
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum Image {
Url(SpecifiedUrl),
Gradient(Gradient),
ImageRect(ImageRect),
Element(Atom),
}
impl fmt::Debug for Image {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Image::Url(ref url) => url.to_css(f),
Image::Gradient(ref grad) => {
if grad.repeating {
let _ = write!(f, "repeating-");
}
match grad.gradient_kind {
GradientKind::Linear(_) => write!(f, "linear-gradient({:?})", grad),
GradientKind::Radial(_, _) => write!(f, "radial-gradient({:?})", grad),
}
},
Image::ImageRect(ref image_rect) => write!(f, "{:?}", image_rect),
Image::Element(ref selector) => {
f.write_str("-moz-element(#")?;
serialize_identifier(&*selector.to_string(), f)?;
f.write_str(")")
},
}
}
}
impl ToCss for Image {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
Image::Url(ref url) => url.to_css(dest),
Image::Gradient(ref gradient) => gradient.to_css(dest),
Image::ImageRect(ref image_rect) => image_rect.to_css(dest),
Image::Element(ref selector) => {
dest.write_str("-moz-element(#")?;
// FIXME: We should get rid of these intermediate strings.
serialize_identifier(&*selector.to_string(), dest)?;
dest.write_str(")")
},
}
}
}
pub type Image = GenericImage<Gradient, ImageRect>;
/// Computed values for a CSS gradient.
/// https://drafts.csswg.org/css-images/#gradients
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Gradient {
/// The color stops.
pub items: Vec<GradientItem>,
/// True if this is a repeating gradient.
pub repeating: bool,
/// Gradient kind can be linear or radial.
pub gradient_kind: GradientKind,
/// Compatibility mode.
pub compat_mode: CompatMode,
}
pub type Gradient = GenericGradient<
LineDirection,
Length,
LengthOrPercentage,
Position,
CSSColor,
>;
impl ToCss for Gradient {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
if self.compat_mode == CompatMode::WebKit {
try!(dest.write_str("-webkit-"));
}
if self.repeating {
try!(dest.write_str("repeating-"));
}
match self.gradient_kind {
GradientKind::Linear(angle_or_corner) => {
try!(dest.write_str("linear-gradient("));
try!(angle_or_corner.to_css(dest, self.compat_mode));
},
GradientKind::Radial(ref shape, position) => {
try!(dest.write_str("radial-gradient("));
try!(shape.to_css(dest));
try!(dest.write_str(" at "));
try!(position.to_css(dest));
},
}
for item in &self.items {
try!(dest.write_str(", "));
try!(item.to_css(dest));
}
try!(dest.write_str(")"));
Ok(())
}
}
impl fmt::Debug for Gradient {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.gradient_kind {
GradientKind::Linear(angle_or_corner) => {
let _ = write!(f, "{:?}", angle_or_corner);
},
GradientKind::Radial(ref shape, position) => {
let _ = write!(f, "{:?} at {:?}", shape, position);
},
}
for item in &self.items {
let _ = write!(f, ", {:?}", item);
}
Ok(())
}
}
impl ToComputedValue for specified::Gradient {
type ComputedValue = Gradient;
#[inline]
fn to_computed_value(&self, context: &Context) -> Gradient {
let specified::Gradient {
ref items,
repeating,
ref gradient_kind,
compat_mode,
} = *self;
Gradient {
items: items.iter().map(|s| s.to_computed_value(context)).collect(),
repeating: repeating,
gradient_kind: gradient_kind.to_computed_value(context),
compat_mode: compat_mode,
}
}
#[inline]
fn from_computed_value(computed: &Gradient) -> Self {
let Gradient {
ref items,
repeating,
ref gradient_kind,
compat_mode,
} = *computed;
specified::Gradient {
items: items.iter().map(ToComputedValue::from_computed_value).collect(),
repeating: repeating,
gradient_kind: ToComputedValue::from_computed_value(gradient_kind),
compat_mode: compat_mode,
}
}
}
/// Computed values for CSS linear or radial gradients.
/// https://drafts.csswg.org/css-images/#gradients
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum GradientKind {
Linear(AngleOrCorner),
Radial(EndingShape, Position),
}
impl ToComputedValue for specified::GradientKind {
type ComputedValue = GradientKind;
#[inline]
fn to_computed_value(&self, context: &Context) -> GradientKind {
match *self {
specified::GradientKind::Linear(angle_or_corner) => {
GradientKind::Linear(angle_or_corner.to_computed_value(context))
},
specified::GradientKind::Radial(ref shape, ref position) => {
GradientKind::Radial(shape.to_computed_value(context),
position.to_computed_value(context))
},
}
}
#[inline]
fn from_computed_value(computed: &GradientKind) -> Self {
match *computed {
GradientKind::Linear(angle_or_corner) => {
specified::GradientKind::Linear(ToComputedValue::from_computed_value(&angle_or_corner))
},
GradientKind::Radial(ref shape, position) => {
specified::GradientKind::Radial(ToComputedValue::from_computed_value(shape),
ToComputedValue::from_computed_value(&position))
},
}
}
}
/// Specified values for color stops and interpolation hints.
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum GradientItem {
/// A color stop.
ColorStop(ColorStop),
/// An interpolation hint.
InterpolationHint(LengthOrPercentage),
}
impl ToCss for GradientItem {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
GradientItem::ColorStop(stop) => stop.to_css(dest),
GradientItem::InterpolationHint(hint) => hint.to_css(dest),
}
}
}
impl ToComputedValue for specified::GradientItem {
type ComputedValue = GradientItem;
#[inline]
fn to_computed_value(&self, context: &Context) -> GradientItem {
match *self {
specified::GradientItem::ColorStop(ref stop) => {
GradientItem::ColorStop(stop.to_computed_value(context))
},
specified::GradientItem::InterpolationHint(ref hint) => {
GradientItem::InterpolationHint(hint.to_computed_value(context))
},
}
}
#[inline]
fn from_computed_value(computed: &GradientItem) -> Self {
match *computed {
GradientItem::ColorStop(ref stop) => {
specified::GradientItem::ColorStop(ToComputedValue::from_computed_value(stop))
},
GradientItem::InterpolationHint(ref hint) => {
specified::GradientItem::InterpolationHint(ToComputedValue::from_computed_value(hint))
},
}
}
}
/// Computed values for one color stop in a linear gradient.
/// https://drafts.csswg.org/css-images/#typedef-color-stop-list
#[derive(Clone, PartialEq, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct ColorStop {
/// The color of this stop.
pub color: CSSColor,
/// The position of this stop. If not specified, this stop is placed halfway between the
/// point that precedes it and the point that follows it per CSS-IMAGES § 3.4.
pub position: Option<LengthOrPercentage>,
}
impl ToCss for ColorStop {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self.color.to_css(dest));
if let Some(position) = self.position {
try!(dest.write_str(" "));
try!(position.to_css(dest));
}
Ok(())
}
}
impl fmt::Debug for ColorStop {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let _ = write!(f, "{:?}", self.color);
self.position.map(|pos| {
let _ = write!(f, " {:?}", pos);
});
Ok(())
}
}
impl ToComputedValue for specified::ColorStop {
type ComputedValue = ColorStop;
#[inline]
fn to_computed_value(&self, context: &Context) -> ColorStop {
ColorStop {
color: self.color.to_computed_value(context),
position: match self.position {
None => None,
Some(ref value) => Some(value.to_computed_value(context)),
},
}
}
#[inline]
fn from_computed_value(computed: &ColorStop) -> Self {
specified::ColorStop {
color: ToComputedValue::from_computed_value(&computed.color),
position: match computed.position {
None => None,
Some(value) => Some(ToComputedValue::from_computed_value(&value)),
},
}
}
}
/// Computed values for EndingShape
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-ending-shape
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum EndingShape {
Circle(LengthOrKeyword),
Ellipse(LengthOrPercentageOrKeyword),
}
impl ToCss for EndingShape {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
EndingShape::Circle(ref length) => {
try!(dest.write_str("circle "));
try!(length.to_css(dest));
},
EndingShape::Ellipse(ref length) => {
try!(dest.write_str("ellipse "));
try!(length.to_css(dest));
},
}
Ok(())
}
}
impl fmt::Debug for EndingShape {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
EndingShape::Circle(ref length) => {
let _ = write!(f, "circle {:?}", length);
},
EndingShape::Ellipse(ref length) => {
let _ = write!(f, "ellipse {:?}", length);
}
}
Ok(())
}
}
impl ToComputedValue for specified::GradientEndingShape {
type ComputedValue = EndingShape;
#[inline]
fn to_computed_value(&self, context: &Context) -> EndingShape {
match *self {
specified::GradientEndingShape::Circle(ref length) => {
EndingShape::Circle(length.to_computed_value(context))
},
specified::GradientEndingShape::Ellipse(ref length) => {
EndingShape::Ellipse(length.to_computed_value(context))
},
}
}
#[inline]
fn from_computed_value(computed: &EndingShape) -> Self {
match *computed {
EndingShape::Circle(ref length) => {
specified::GradientEndingShape::Circle(ToComputedValue::from_computed_value(length))
},
EndingShape::Ellipse(ref length) => {
specified::GradientEndingShape::Ellipse(ToComputedValue::from_computed_value(length))
},
}
}
}
/// Computed values for ImageRect
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct ImageRect {
pub url: SpecifiedUrl,
pub top: NumberOrPercentage,
pub bottom: NumberOrPercentage,
pub right: NumberOrPercentage,
pub left: NumberOrPercentage,
}
impl ToCss for ImageRect {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
dest.write_str("-moz-image-rect(")?;
self.url.to_css(dest)?;
dest.write_str(", ")?;
self.top.to_css(dest)?;
dest.write_str(", ")?;
self.right.to_css(dest)?;
dest.write_str(", ")?;
self.bottom.to_css(dest)?;
dest.write_str(", ")?;
self.left.to_css(dest)?;
dest.write_str(")")
}
}
impl ToComputedValue for specified::ImageRect {
type ComputedValue = ImageRect;
#[inline]
fn to_computed_value(&self, context: &Context) -> ImageRect {
ImageRect {
url: self.url.to_computed_value(context),
top: self.top.to_computed_value(context),
right: self.right.to_computed_value(context),
bottom: self.bottom.to_computed_value(context),
left: self.left.to_computed_value(context),
}
}
#[inline]
fn from_computed_value(computed: &ImageRect) -> Self {
specified::ImageRect {
url: ToComputedValue::from_computed_value(&computed.url),
top: ToComputedValue::from_computed_value(&computed.top),
right: ToComputedValue::from_computed_value(&computed.right),
bottom: ToComputedValue::from_computed_value(&computed.bottom),
left: ToComputedValue::from_computed_value(&computed.left),
}
}
}
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrKeyword {
Length(Length),
Keyword(SizeKeyword),
}
impl ToCss for LengthOrKeyword {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
LengthOrKeyword::Length(ref length) => length.to_css(dest),
LengthOrKeyword::Keyword(keyword) => keyword.to_css(dest),
}
}
}
impl fmt::Debug for LengthOrKeyword {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
LengthOrKeyword::Length(ref length) => {
let _ = write!(f, "{:?}", length);
},
LengthOrKeyword::Keyword(keyword) => {
let _ = write!(f, "{:?}", keyword);
},
}
Ok(())
}
}
impl ToComputedValue for specified::LengthOrKeyword {
type ComputedValue = LengthOrKeyword;
#[inline]
fn to_computed_value(&self, context: &Context) -> LengthOrKeyword {
match *self {
specified::LengthOrKeyword::Length(ref length) => {
LengthOrKeyword::Length(length.to_computed_value(context))
},
specified::LengthOrKeyword::Keyword(keyword) => {
LengthOrKeyword::Keyword(keyword)
},
}
}
#[inline]
fn from_computed_value(computed: &LengthOrKeyword) -> Self {
match *computed {
LengthOrKeyword::Length(length) => {
specified::LengthOrKeyword::Length(ToComputedValue::from_computed_value(&length))
},
LengthOrKeyword::Keyword(keyword) => {
specified::LengthOrKeyword::Keyword(keyword)
},
}
}
}
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrPercentageOrKeyword {
LengthOrPercentage(LengthOrPercentage, LengthOrPercentage),
Keyword(SizeKeyword),
}
impl ToCss for LengthOrPercentageOrKeyword {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
LengthOrPercentageOrKeyword::LengthOrPercentage(ref first_len, second_len) => {
try!(first_len.to_css(dest));
try!(dest.write_str(" "));
second_len.to_css(dest)
},
LengthOrPercentageOrKeyword::Keyword(keyword) => keyword.to_css(dest),
}
}
}
impl fmt::Debug for LengthOrPercentageOrKeyword {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
LengthOrPercentageOrKeyword::LengthOrPercentage(ref first_len, second_len) => {
let _ = write!(f, "{:?} {:?}", first_len, second_len);
},
LengthOrPercentageOrKeyword::Keyword(keyword) => {
let _ = write!(f, "{:?}", keyword);
},
}
Ok(())
}
}
impl ToComputedValue for specified::LengthOrPercentageOrKeyword {
type ComputedValue = LengthOrPercentageOrKeyword;
#[inline]
fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrKeyword {
match *self {
specified::LengthOrPercentageOrKeyword::LengthOrPercentage(ref first_len, ref second_len) => {
LengthOrPercentageOrKeyword::LengthOrPercentage(first_len.to_computed_value(context),
second_len.to_computed_value(context))
},
specified::LengthOrPercentageOrKeyword::Keyword(keyword) => {
LengthOrPercentageOrKeyword::Keyword(keyword)
},
}
}
#[inline]
fn from_computed_value(computed: &LengthOrPercentageOrKeyword) -> Self {
match *computed {
LengthOrPercentageOrKeyword::LengthOrPercentage(first_len, second_len) => {
specified::LengthOrPercentageOrKeyword::LengthOrPercentage(
ToComputedValue::from_computed_value(&first_len),
ToComputedValue::from_computed_value(&second_len))
},
LengthOrPercentageOrKeyword::Keyword(keyword) => {
specified::LengthOrPercentageOrKeyword::Keyword(keyword)
},
}
}
}
/// A computed gradient kind.
pub type GradientKind = GenericGradientKind<
LineDirection,
Length,
LengthOrPercentage,
Position,
>;
/// A computed gradient line direction.
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum AngleOrCorner {
pub enum LineDirection {
/// An angle.
Angle(Angle),
Corner(HorizontalDirection, VerticalDirection)
/// A corner.
Corner(X, Y),
}
impl ToComputedValue for specified::AngleOrCorner {
type ComputedValue = AngleOrCorner;
/// A computed radial gradient ending shape.
pub type EndingShape = GenericEndingShape<Length, LengthOrPercentage>;
#[inline]
fn to_computed_value(&self, context: &Context) -> AngleOrCorner {
/// A computed gradient item.
pub type GradientItem = GenericGradientItem<CSSColor, LengthOrPercentage>;
/// A computed color stop.
pub type ColorStop = GenericColorStop<CSSColor, LengthOrPercentage>;
/// Computed values for ImageRect.
pub type ImageRect = GenericImageRect<NumberOrPercentage>;
impl GenericLineDirection for LineDirection {
fn points_downwards(&self) -> bool {
match *self {
specified::AngleOrCorner::None => {
AngleOrCorner::Angle(Angle::from_radians(PI))
},
specified::AngleOrCorner::Angle(angle) => {
AngleOrCorner::Angle(angle.to_computed_value(context))
},
specified::AngleOrCorner::Corner(horizontal, vertical) => {
match (horizontal, vertical) {
(None, Some(VerticalDirection::Top)) => {
AngleOrCorner::Angle(Angle::from_radians(0.0))
},
(Some(HorizontalDirection::Right), None) => {
AngleOrCorner::Angle(Angle::from_radians(PI * 0.5))
},
(None, Some(VerticalDirection::Bottom)) => {
AngleOrCorner::Angle(Angle::from_radians(PI))
},
(Some(HorizontalDirection::Left), None) => {
AngleOrCorner::Angle(Angle::from_radians(PI * 1.5))
},
(Some(horizontal), Some(vertical)) => {
AngleOrCorner::Corner(horizontal, vertical)
},
(None, None) => {
unreachable!()
}
}
}
LineDirection::Angle(angle) => angle.radians() == PI,
LineDirection::Corner(..) => false,
}
}
#[inline]
fn from_computed_value(computed: &AngleOrCorner) -> Self {
fn to_css<W>(&self, dest: &mut W, compat_mode: CompatMode) -> fmt::Result
where W: fmt::Write
{
match *self {
LineDirection::Angle(ref angle) => angle.to_css(dest),
LineDirection::Corner(x, y) => {
if compat_mode == CompatMode::Modern {
dest.write_str("to ")?;
}
x.to_css(dest)?;
dest.write_str(" ")?;
y.to_css(dest)
},
}
}
}
impl ToComputedValue for SpecifiedLineDirection {
type ComputedValue = LineDirection;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
SpecifiedLineDirection::Angle(ref angle) => {
LineDirection::Angle(angle.to_computed_value(context))
},
SpecifiedLineDirection::Horizontal(X::Left) => {
LineDirection::Angle(Angle::Degree(270.))
},
SpecifiedLineDirection::Horizontal(X::Right) => {
LineDirection::Angle(Angle::Degree(90.))
},
SpecifiedLineDirection::Vertical(Y::Top) => {
LineDirection::Angle(Angle::Degree(0.))
},
SpecifiedLineDirection::Vertical(Y::Bottom) => {
LineDirection::Angle(Angle::Degree(180.))
},
SpecifiedLineDirection::Corner(x, y) => {
LineDirection::Corner(x, y)
},
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
AngleOrCorner::Angle(ref angle) => {
specified::AngleOrCorner::Angle(specified::Angle::from_computed_value(angle))
LineDirection::Angle(ref angle) => {
SpecifiedLineDirection::Angle(ToComputedValue::from_computed_value(angle))
},
LineDirection::Corner(x, y) => {
SpecifiedLineDirection::Corner(x, y)
},
AngleOrCorner::Corner(horizontal, vertical) => {
specified::AngleOrCorner::Corner(Some(horizontal), Some(vertical))
}
}
}
}
impl AngleOrCorner {
fn to_css<W>(&self, dest: &mut W, mode: CompatMode) -> fmt::Result where W: fmt::Write {
match *self {
AngleOrCorner::Angle(angle) => angle.to_css(dest),
AngleOrCorner::Corner(horizontal, vertical) => {
if mode == CompatMode::Modern {
try!(dest.write_str("to "));
}
try!(horizontal.to_css(dest));
try!(dest.write_str(" "));
try!(vertical.to_css(dest));
Ok(())
}
}
}
}
/// Computed values for none | <image> | <mask-source>.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct LayerImage(pub Option<Image>);
impl ToCss for LayerImage {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match self.0 {
None => dest.write_str("none"),
Some(ref image) => image.to_css(dest),
}
}
}

View File

@ -12,8 +12,7 @@ use super::{Number, ToComputedValue, Context};
use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength, ViewportPercentageLength};
pub use super::image::{EndingShape as GradientShape, Gradient, GradientKind, Image};
pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
pub use super::image::Image;
pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
impl ToComputedValue for specified::NoCalcLength {

View File

@ -22,8 +22,7 @@ use super::specified::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as G
pub use app_units::Au;
pub use cssparser::Color as CSSColor;
pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientItem, LayerImage};
pub use self::image::{GradientKind, Image, ImageRect, LengthOrKeyword, LengthOrPercentageOrKeyword};
pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect};
pub use super::{Auto, Either, None_};
#[cfg(feature = "gecko")]
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};

View File

@ -0,0 +1,636 @@
/* 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/. */
//! Generic types for the handling of [images].
//!
//! [images]: https://drafts.csswg.org/css-images/#image-values
use Atom;
use cssparser::serialize_identifier;
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
use values::computed::{Context, ToComputedValue};
use values::specified::url::SpecifiedUrl;
/// An [image].
///
/// [image]: https://drafts.csswg.org/css-images/#image-values
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Image<Gradient, ImageRect> {
/// A `<url()>` image.
Url(SpecifiedUrl),
/// A `<gradient>` image.
Gradient(Gradient),
/// A `-moz-image-rect` image
Rect(ImageRect),
/// A `-moz-element(# <element-id>)`
Element(Atom),
}
/// A CSS gradient.
/// https://drafts.csswg.org/css-images/#gradients
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color> {
/// Gradients can be linear or radial.
pub kind: GradientKind<LineDirection, Length, LengthOrPercentage, Position>,
/// The color stops and interpolation hints.
pub items: Vec<GradientItem<Color, LengthOrPercentage>>,
/// True if this is a repeating gradient.
pub repeating: bool,
/// Compatibility mode.
pub compat_mode: CompatMode,
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// Whether we used the modern notation or the compatibility `-webkit` prefix.
pub enum CompatMode {
/// Modern syntax.
Modern,
/// `-webkit` prefix.
WebKit,
}
/// A gradient kind.
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum GradientKind<LineDirection, Length, LengthOrPercentage, Position> {
/// A linear gradient.
Linear(LineDirection),
/// A radial gradient.
Radial(EndingShape<Length, LengthOrPercentage>, Position),
}
/// A radial gradient's ending shape.
#[derive(Clone, Copy, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum EndingShape<Length, LengthOrPercentage> {
/// A circular gradient.
Circle(Circle<Length>),
/// An elliptic gradient.
Ellipse(Ellipse<LengthOrPercentage>),
}
/// A circle shape.
#[derive(Clone, Copy, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Circle<Length> {
/// A circle radius.
Radius(Length),
/// A circle extent.
Extent(ShapeExtent),
}
/// An ellipse shape.
#[derive(Clone, Copy, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Ellipse<LengthOrPercentage> {
/// An ellipse pair of radii.
Radii(LengthOrPercentage, LengthOrPercentage),
/// An ellipse extent.
Extent(ShapeExtent),
}
/// https://drafts.csswg.org/css-images/#typedef-extent-keyword
define_css_keyword_enum!(ShapeExtent:
"closest-side" => ClosestSide,
"farthest-side" => FarthestSide,
"closest-corner" => ClosestCorner,
"farthest-corner" => FarthestCorner,
"contain" => Contain,
"cover" => Cover
);
/// A gradient item.
/// https://drafts.csswg.org/css-images-4/#color-stop-syntax
#[derive(Clone, Copy, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum GradientItem<Color, LengthOrPercentage> {
/// A color stop.
ColorStop(ColorStop<Color, LengthOrPercentage>),
/// An interpolation hint.
InterpolationHint(LengthOrPercentage),
}
/// A color stop.
/// https://drafts.csswg.org/css-images/#typedef-color-stop-list
#[derive(Clone, Copy, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct ColorStop<Color, LengthOrPercentage> {
/// The color of this stop.
pub color: Color,
/// The position of this stop.
pub position: Option<LengthOrPercentage>,
}
/// Values for `moz-image-rect`.
///
/// `-moz-image-rect(<uri>, top, right, bottom, left);`
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct ImageRect<NumberOrPercentage> {
pub url: SpecifiedUrl,
pub top: NumberOrPercentage,
pub bottom: NumberOrPercentage,
pub right: NumberOrPercentage,
pub left: NumberOrPercentage,
}
impl<G, R> fmt::Debug for Image<G, R>
where G: fmt::Debug, R: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Image::Url(ref url) => url.to_css(f),
Image::Gradient(ref grad) => grad.fmt(f),
Image::Rect(ref rect) => rect.fmt(f),
Image::Element(ref selector) => {
f.write_str("-moz-element(#")?;
serialize_identifier(&selector.to_string(), f)?;
f.write_str(")")
},
}
}
}
impl<G, R> ToCss for Image<G, R>
where G: ToCss, R: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
Image::Url(ref url) => url.to_css(dest),
Image::Gradient(ref gradient) => gradient.to_css(dest),
Image::Rect(ref rect) => rect.to_css(dest),
Image::Element(ref selector) => {
dest.write_str("-moz-element(#")?;
serialize_identifier(&selector.to_string(), dest)?;
dest.write_str(")")
},
}
}
}
impl<G, R> HasViewportPercentage for Image<G, R>
where G: HasViewportPercentage
{
fn has_viewport_percentage(&self) -> bool {
match *self {
Image::Gradient(ref gradient) => gradient.has_viewport_percentage(),
_ => false,
}
}
}
impl<G, R> ToComputedValue for Image<G, R>
where G: ToComputedValue, R: ToComputedValue,
{
type ComputedValue = Image<<G as ToComputedValue>::ComputedValue,
<R as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
Image::Url(ref url) => {
Image::Url(url.clone())
},
Image::Gradient(ref gradient) => {
Image::Gradient(gradient.to_computed_value(context))
},
Image::Rect(ref rect) => {
Image::Rect(rect.to_computed_value(context))
},
Image::Element(ref selector) => {
Image::Element(selector.clone())
}
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
Image::Url(ref url) => {
Image::Url(url.clone())
},
Image::Gradient(ref gradient) => {
Image::Gradient(ToComputedValue::from_computed_value(gradient))
},
Image::Rect(ref rect) => {
Image::Rect(ToComputedValue::from_computed_value(rect))
},
Image::Element(ref selector) => {
Image::Element(selector.clone())
},
}
}
}
impl<D, L, LoP, P, C> ToCss for Gradient<D, L, LoP, P, C>
where D: LineDirection, L: ToCss, LoP: ToCss, P: ToCss, C: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
if self.compat_mode == CompatMode::WebKit {
dest.write_str("-webkit-")?;
}
if self.repeating {
dest.write_str("repeating-")?;
}
dest.write_str(self.kind.label())?;
dest.write_str("-gradient(")?;
let mut skip_comma = match self.kind {
GradientKind::Linear(ref direction) if direction.points_downwards() => true,
GradientKind::Linear(ref direction) => {
direction.to_css(dest, self.compat_mode)?;
false
},
GradientKind::Radial(ref shape, ref position) => {
let omit_shape = match *shape {
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::Cover)) |
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) => {
true
},
_ => false,
};
if self.compat_mode == CompatMode::Modern {
if !omit_shape {
shape.to_css(dest)?;
dest.write_str(" ")?;
}
dest.write_str("at ")?;
position.to_css(dest)?;
} else {
position.to_css(dest)?;
if !omit_shape {
dest.write_str(", ")?;
shape.to_css(dest)?;
}
}
false
},
};
for item in &self.items {
if !skip_comma {
dest.write_str(", ")?;
}
skip_comma = false;
item.to_css(dest)?;
}
dest.write_str(")")
}
}
impl<D, L, LoP, P, C> HasViewportPercentage for Gradient<D, L, LoP, P, C>
where L: HasViewportPercentage,
LoP: HasViewportPercentage,
P: HasViewportPercentage,
{
fn has_viewport_percentage(&self) -> bool {
self.kind.has_viewport_percentage() ||
self.items.iter().any(|i| i.has_viewport_percentage())
}
}
impl<D, L, LoP, P, C> ToComputedValue for Gradient<D, L, LoP, P, C>
where D: ToComputedValue,
L: ToComputedValue,
LoP: ToComputedValue,
P: ToComputedValue,
C: ToComputedValue,
{
type ComputedValue = Gradient<<D as ToComputedValue>::ComputedValue,
<L as ToComputedValue>::ComputedValue,
<LoP as ToComputedValue>::ComputedValue,
<P as ToComputedValue>::ComputedValue,
<C as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
Gradient {
kind: self.kind.to_computed_value(context),
items: self.items.iter().map(|s| s.to_computed_value(context)).collect(),
repeating: self.repeating,
compat_mode: self.compat_mode,
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Gradient {
kind: ToComputedValue::from_computed_value(&computed.kind),
items: computed.items.iter().map(ToComputedValue::from_computed_value).collect(),
repeating: computed.repeating,
compat_mode: computed.compat_mode,
}
}
}
impl<D, L, LoP, P> GradientKind<D, L, LoP, P> {
fn label(&self) -> &str {
match *self {
GradientKind::Linear(..) => "linear",
GradientKind::Radial(..) => "radial",
}
}
}
impl<D, L, LoP, P> HasViewportPercentage for GradientKind<D, L, LoP, P>
where L: HasViewportPercentage,
LoP: HasViewportPercentage,
P: HasViewportPercentage
{
fn has_viewport_percentage(&self) -> bool {
match *self {
GradientKind::Linear(_) => false,
GradientKind::Radial(ref shape, ref position) => {
shape.has_viewport_percentage() || position.has_viewport_percentage()
},
}
}
}
impl<D, L, LoP, P> ToComputedValue for GradientKind<D, L, LoP, P>
where D: ToComputedValue,
L: ToComputedValue,
LoP: ToComputedValue,
P: ToComputedValue,
{
type ComputedValue = GradientKind<<D as ToComputedValue>::ComputedValue,
<L as ToComputedValue>::ComputedValue,
<LoP as ToComputedValue>::ComputedValue,
<P as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
GradientKind::Linear(ref direction) => {
GradientKind::Linear(direction.to_computed_value(context))
},
GradientKind::Radial(ref shape, ref position) => {
GradientKind::Radial(shape.to_computed_value(context), position.to_computed_value(context))
},
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
GradientKind::Linear(ref direction) => {
GradientKind::Linear(ToComputedValue::from_computed_value(direction))
},
GradientKind::Radial(ref shape, ref position) => {
GradientKind::Radial(
ToComputedValue::from_computed_value(shape),
ToComputedValue::from_computed_value(position),
)
}
}
}
}
/// The direction of a linear gradient.
pub trait LineDirection {
/// Whether this direction points towards, and thus can be omitted.
fn points_downwards(&self) -> bool;
/// Serialises this direction according to the compatibility mode.
fn to_css<W>(&self, dest: &mut W, compat_mode: CompatMode) -> fmt::Result
where W: fmt::Write;
}
impl<L, LoP> ToCss for EndingShape<L, LoP>
where L: ToCss, LoP: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
EndingShape::Circle(Circle::Extent(ShapeExtent::FarthestCorner)) |
EndingShape::Circle(Circle::Extent(ShapeExtent::Cover)) => {
dest.write_str("circle")
},
EndingShape::Circle(Circle::Extent(keyword)) => {
dest.write_str("circle ")?;
keyword.to_css(dest)
},
EndingShape::Circle(Circle::Radius(ref length)) => {
length.to_css(dest)
},
EndingShape::Ellipse(Ellipse::Extent(keyword)) => {
keyword.to_css(dest)
},
EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => {
x.to_css(dest)?;
dest.write_str(" ")?;
y.to_css(dest)
},
}
}
}
impl<L, LoP> HasViewportPercentage for EndingShape<L, LoP>
where L: HasViewportPercentage, LoP: HasViewportPercentage,
{
fn has_viewport_percentage(&self) -> bool {
match *self {
EndingShape::Circle(Circle::Radius(ref length)) => {
length.has_viewport_percentage()
},
EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => {
x.has_viewport_percentage() || y.has_viewport_percentage()
},
_ => false,
}
}
}
impl<L, LoP> ToComputedValue for EndingShape<L, LoP>
where L: ToComputedValue, LoP: ToComputedValue,
{
type ComputedValue = EndingShape<<L as ToComputedValue>::ComputedValue,
<LoP as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
EndingShape::Circle(Circle::Radius(ref length)) => {
EndingShape::Circle(Circle::Radius(length.to_computed_value(context)))
},
EndingShape::Circle(Circle::Extent(extent)) => {
EndingShape::Circle(Circle::Extent(extent))
},
EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => {
EndingShape::Ellipse(Ellipse::Radii(
x.to_computed_value(context),
y.to_computed_value(context),
))
},
EndingShape::Ellipse(Ellipse::Extent(extent)) => {
EndingShape::Ellipse(Ellipse::Extent(extent))
},
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
EndingShape::Circle(Circle::Radius(ref length)) => {
EndingShape::Circle(Circle::Radius(ToComputedValue::from_computed_value(length)))
},
EndingShape::Circle(Circle::Extent(extent)) => {
EndingShape::Circle(Circle::Extent(extent))
},
EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => {
EndingShape::Ellipse(Ellipse::Radii(
ToComputedValue::from_computed_value(x),
ToComputedValue::from_computed_value(y),
))
},
EndingShape::Ellipse(Ellipse::Extent(extent)) => {
EndingShape::Ellipse(Ellipse::Extent(extent))
},
}
}
}
impl<C, L> ToCss for GradientItem<C, L>
where C: ToCss, L: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
GradientItem::ColorStop(ref stop) => stop.to_css(dest),
GradientItem::InterpolationHint(ref hint) => hint.to_css(dest),
}
}
}
impl<C, L> HasViewportPercentage for GradientItem<C, L>
where L: HasViewportPercentage,
{
fn has_viewport_percentage(&self) -> bool {
match *self {
GradientItem::ColorStop(ref stop) => stop.has_viewport_percentage(),
GradientItem::InterpolationHint(ref hint) => hint.has_viewport_percentage(),
}
}
}
impl<C, L> ToComputedValue for GradientItem<C, L>
where C: ToComputedValue, L: ToComputedValue,
{
type ComputedValue = GradientItem<<C as ToComputedValue>::ComputedValue,
<L as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
GradientItem::ColorStop(ref stop) => {
GradientItem::ColorStop(stop.to_computed_value(context))
},
GradientItem::InterpolationHint(ref hint) => {
GradientItem::InterpolationHint(hint.to_computed_value(context))
},
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
GradientItem::ColorStop(ref stop) => {
GradientItem::ColorStop(ToComputedValue::from_computed_value(stop))
},
GradientItem::InterpolationHint(ref hint) => {
GradientItem::InterpolationHint(ToComputedValue::from_computed_value(hint))
},
}
}
}
impl<C, L> fmt::Debug for ColorStop<C, L>
where C: fmt::Debug, L: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.color)?;
if let Some(ref pos) = self.position {
write!(f, " {:?}", pos)?;
}
Ok(())
}
}
impl<C, L> ToCss for ColorStop<C, L>
where C: ToCss, L: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.color.to_css(dest)?;
if let Some(ref position) = self.position {
dest.write_str(" ")?;
position.to_css(dest)?;
}
Ok(())
}
}
impl<C, L> HasViewportPercentage for ColorStop<C, L>
where L: HasViewportPercentage,
{
fn has_viewport_percentage(&self) -> bool {
self.position.as_ref().map_or(false, HasViewportPercentage::has_viewport_percentage)
}
}
impl<C, L> ToComputedValue for ColorStop<C, L>
where C: ToComputedValue, L: ToComputedValue,
{
type ComputedValue = ColorStop<<C as ToComputedValue>::ComputedValue,
<L as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
ColorStop {
color: self.color.to_computed_value(context),
position: self.position.as_ref().map(|p| p.to_computed_value(context)),
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
ColorStop {
color: ToComputedValue::from_computed_value(&computed.color),
position: computed.position.as_ref().map(ToComputedValue::from_computed_value),
}
}
}
impl<C> ToCss for ImageRect<C>
where C: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
dest.write_str("-moz-image-rect(")?;
self.url.to_css(dest)?;
dest.write_str(", ")?;
self.top.to_css(dest)?;
dest.write_str(", ")?;
self.right.to_css(dest)?;
dest.write_str(", ")?;
self.bottom.to_css(dest)?;
dest.write_str(", ")?;
self.left.to_css(dest)?;
dest.write_str(")")
}
}
impl<C> ToComputedValue for ImageRect<C>
where C: ToComputedValue,
{
type ComputedValue = ImageRect<<C as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
ImageRect {
url: self.url.to_computed_value(context),
top: self.top.to_computed_value(context),
right: self.right.to_computed_value(context),
bottom: self.bottom.to_computed_value(context),
left: self.left.to_computed_value(context),
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
ImageRect {
url: ToComputedValue::from_computed_value(&computed.url),
top: ToComputedValue::from_computed_value(&computed.top),
right: ToComputedValue::from_computed_value(&computed.right),
bottom: ToComputedValue::from_computed_value(&computed.bottom),
left: ToComputedValue::from_computed_value(&computed.left),
}
}
}

View File

@ -14,6 +14,7 @@ use super::computed::{Context, ToComputedValue};
pub use self::basic_shape::serialize_radius_values;
pub mod basic_shape;
pub mod image;
pub mod position;
#[derive(Clone, PartialEq, Debug)]

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,7 @@ use std::{cmp, fmt, mem};
use std::ascii::AsciiExt;
use std::ops::Mul;
use style_traits::ToCss;
use style_traits::values::specified::AllowedLengthType;
use style_traits::values::specified::{AllowedLengthType, AllowedNumericType};
use stylesheets::CssRuleType;
use super::{AllowQuirks, Number, ToComputedValue};
use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_, Normal};
@ -24,9 +24,8 @@ use values::computed::{ComputedValueAsSpecified, Context};
use values::specified::calc::CalcNode;
pub use values::specified::calc::CalcLengthOrPercentage;
pub use super::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
pub use super::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword};
pub use super::image::{SizeKeyword, VerticalDirection};
pub use super::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
pub use super::image::{GradientKind, Image};
/// Number of app units per pixel
pub const AU_PER_PX: CSSFloat = 60.;
@ -730,7 +729,10 @@ impl ToCss for Percentage {
}
impl Percentage {
fn parse_internal(input: &mut Parser, context: AllowedLengthType) -> Result<Self, ()> {
/// Parse a specific kind of percentage.
pub fn parse_with_clamping_mode(input: &mut Parser,
context: AllowedNumericType)
-> Result<Self, ()> {
match try!(input.next()) {
Token::Percentage(ref value) if context.is_ok(value.unit_value) => {
Ok(Percentage(value.unit_value))
@ -741,14 +743,14 @@ impl Percentage {
/// Parses a percentage token, but rejects it if it's negative.
pub fn parse_non_negative(input: &mut Parser) -> Result<Self, ()> {
Self::parse_internal(input, AllowedLengthType::NonNegative)
Self::parse_with_clamping_mode(input, AllowedNumericType::NonNegative)
}
}
impl Parse for Percentage {
#[inline]
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Self::parse_internal(input, AllowedLengthType::All)
Self::parse_with_clamping_mode(input, AllowedNumericType::All)
}
}

View File

@ -28,9 +28,8 @@ use values::specified::calc::CalcNode;
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
pub use self::color::Color;
pub use self::grid::{GridLine, TrackKeyword};
pub use self::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
pub use self::image::{GradientItem, GradientKind, HorizontalDirection, Image, ImageRect, LayerImage};
pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword, SizeKeyword, VerticalDirection};
pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
pub use self::image::{GradientItem, GradientKind, Image, ImageRect, ImageLayer};
pub use self::length::AbsoluteLength;
pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
@ -681,7 +680,7 @@ impl ToCss for Number {
/// <number-percentage>
/// Accepts only non-negative numbers.
#[derive(Debug, Clone, PartialEq)]
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum NumberOrPercentage {
@ -691,13 +690,27 @@ pub enum NumberOrPercentage {
no_viewport_percentage!(NumberOrPercentage);
impl Parse for NumberOrPercentage {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(per) = input.try(Percentage::parse_non_negative) {
impl NumberOrPercentage {
fn parse_with_clamping_mode(context: &ParserContext,
input: &mut Parser,
type_: AllowedNumericType)
-> Result<Self, ()> {
if let Ok(per) = input.try(|i| Percentage::parse_with_clamping_mode(i, type_)) {
return Ok(NumberOrPercentage::Percentage(per));
}
Number::parse_non_negative(context, input).map(NumberOrPercentage::Number)
parse_number_with_clamping_mode(context, input, type_).map(NumberOrPercentage::Number)
}
/// Parse a non-negative number or percentage.
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
}
}
impl Parse for NumberOrPercentage {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Self::parse_with_clamping_mode(context, input, AllowedNumericType::All)
}
}

View File

@ -571,7 +571,8 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
data: *const nsACString,
mode: SheetParsingMode,
media_list: *const RawServoMediaList,
extra_data: *mut URLExtraData)
extra_data: *mut URLExtraData,
line_number_offset: u32)
-> RawServoStyleSheetStrong {
let global_style_data = &*GLOBAL_STYLE_DATA;
let input = unsafe { data.as_ref().unwrap().as_str_unchecked() };
@ -605,7 +606,8 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
Arc::new(Stylesheet::from_str(
input, url_data.clone(), origin, media,
shared_lock, loader, &RustLogReporter, QuirksMode::NoQuirks, 0u64)
shared_lock, loader, &RustLogReporter,
QuirksMode::NoQuirks, line_number_offset as u64)
).into_strong()
}
@ -614,7 +616,8 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet
loader: *mut Loader,
gecko_stylesheet: *mut ServoStyleSheet,
data: *const nsACString,
extra_data: *mut URLExtraData)
extra_data: *mut URLExtraData,
line_number_offset: u32)
{
let input = unsafe { data.as_ref().unwrap().as_str_unchecked() };
let url_data = unsafe { RefPtr::from_ptr_ref(&extra_data) };
@ -632,8 +635,8 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet
};
let sheet = Stylesheet::as_arc(&stylesheet);
Stylesheet::update_from_str(&sheet, input, url_data,
loader, &RustLogReporter);
Stylesheet::update_from_str(&sheet, input, url_data, loader,
&RustLogReporter, line_number_offset as u64);
}
#[no_mangle]
@ -782,16 +785,24 @@ macro_rules! impl_basic_rule_funcs {
to_css: $to_css:ident,
} => {
#[no_mangle]
pub extern "C" fn $getter(rules: ServoCssRulesBorrowed, index: u32) -> Strong<$raw_type> {
read_locked_arc(rules, |rules: &CssRules| {
match rules.0[index as usize] {
CssRule::$name(ref rule) => rule.clone().into_strong(),
_ => {
unreachable!(concat!(stringify!($getter), "should only be called ",
"on a ", stringify!($name), " rule"));
}
pub extern "C" fn $getter(rules: ServoCssRulesBorrowed, index: u32,
line: *mut u32, column: *mut u32)
-> Strong<$raw_type> {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rules = Locked::<CssRules>::as_arc(&rules).read_with(&guard);
match rules.0[index as usize] {
CssRule::$name(ref rule) => {
let location = rule.read_with(&guard).source_location;
*unsafe { line.as_mut().unwrap() } = location.line as u32;
*unsafe { column.as_mut().unwrap() } = location.column as u32;
rule.clone().into_strong()
},
_ => {
unreachable!(concat!(stringify!($getter), "should only be called ",
"on a ", stringify!($name), " rule"));
}
})
}
}
#[no_mangle]
@ -924,7 +935,7 @@ pub extern "C" fn Servo_NamespaceRule_GetURI(rule: RawServoNamespaceRuleBorrowed
#[no_mangle]
pub extern "C" fn Servo_PageRule_GetStyle(rule: RawServoPageRuleBorrowed) -> RawServoDeclarationBlockStrong {
read_locked_arc(rule, |rule: &PageRule| {
rule.0.clone().into_strong()
rule.block.clone().into_strong()
})
}
@ -933,7 +944,7 @@ pub extern "C" fn Servo_PageRule_SetStyle(rule: RawServoPageRuleBorrowed,
declarations: RawServoDeclarationBlockBorrowed) {
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
write_locked_arc(rule, |rule: &mut PageRule| {
rule.0 = declarations.clone();
rule.block = declarations.clone();
})
}
@ -1824,8 +1835,8 @@ pub extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(declarations:
raw_extra_data: *mut URLExtraData) {
use style::properties::PropertyDeclaration;
use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
use style::properties::longhands::background_image::single_value::SpecifiedValue as SingleBackgroundImage;
use style::values::specified::image::Image;
use style::values::Either;
use style::values::generics::image::Image;
use style::values::specified::url::SpecifiedUrl;
let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) };
@ -1836,9 +1847,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(declarations:
QuirksMode::NoQuirks);
if let Ok(url) = SpecifiedUrl::parse_from_string(string.into(), &context) {
let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(
vec![SingleBackgroundImage(
Some(Image::Url(url))
)]
vec![Either::Second(Image::Url(url))]
));
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(decl, Importance::Normal);

View File

@ -10,6 +10,7 @@ path = "lib.rs"
doctest = false
[dependencies]
cssparser = "0.13.3"
gfx = {path = "../../../components/gfx"}
ipc-channel = "0.7"
style = {path = "../../../components/style"}

View File

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cssparser::SourceLocation;
use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::ipc;
use style::computed_values::font_family::FamilyName;
@ -23,6 +24,10 @@ fn test_local_web_font() {
let font_face_rule = FontFaceRuleData {
family: Some(family_name.clone()),
sources: Some(vec![Source::Local(variant_name)]),
source_location: SourceLocation {
line: 0,
column: 0,
},
};
font_cache_thread.add_web_font(

View File

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
extern crate cssparser;
extern crate gfx;
extern crate ipc_channel;
extern crate style;

View File

@ -2,16 +2,8 @@
* 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 euclid::size::TypedSize2D;
use parsing::parse;
use std::f32::consts::PI;
use style::context::QuirksMode;
use style::font_metrics::ServoMetricsProvider;
use style::media_queries::{Device, MediaType};
use style::properties::{ComputedValues, StyleBuilder};
use style::values::computed;
use style::values::computed::{Angle, Context, ToComputedValue};
use style::values::specified;
use style::parser::Parse;
use style::values::specified::image::*;
use style_traits::ToCss;
@ -37,101 +29,77 @@ fn test_linear_gradient() {
// Parsing without <angle> and <side-or-corner>
assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, green)");
// AngleOrCorner::None should become AngleOrCorner::Angle(Angle(PI)) when parsed
// Note that Angle(PI) is correct for top-to-bottom rendering, whereas Angle(0) would render bottom-to-top.
// ref: https://developer.mozilla.org/en-US/docs/Web/CSS/angle
let viewport_size = TypedSize2D::new(0., 0.);
let initial_style = ComputedValues::initial_values();
let device = Device::new(MediaType::Screen, viewport_size);
let specified_context = Context {
is_root_element: true,
device: &device,
inherited_style: initial_style,
layout_parent_style: initial_style,
style: StyleBuilder::for_derived_style(&initial_style),
cached_system_font: None,
font_metrics_provider: &ServoMetricsProvider,
in_media_query: false,
quirks_mode: QuirksMode::NoQuirks,
};
assert_eq!(specified::AngleOrCorner::None.to_computed_value(&specified_context),
computed::AngleOrCorner::Angle(Angle::from_radians(PI)));
}
#[test]
fn test_radial_gradient() {
// Parsing with all values
assert_roundtrip_with_context!(Image::parse, "radial-gradient(circle closest-side at 20px 30px, red, green)");
assert_roundtrip_with_context!(Image::parse, "radial-gradient(ellipse closest-side at 20px 30px, red, green)");
assert_roundtrip_with_context!(Image::parse, "radial-gradient(ellipse closest-side at 20px 30px, red, green)",
"radial-gradient(closest-side at 20px 30px, red, green)");
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-side circle at 20px 30px, red, green)",
"radial-gradient(circle closest-side at 20px 30px, red, green)");
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-side ellipse at 20px 30px, red, green)",
"radial-gradient(ellipse closest-side at 20px 30px, red, green)");
"radial-gradient(closest-side at 20px 30px, red, green)");
// Parsing with <shape-keyword> and <size> reversed
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-side circle at 20px 30px, red, green)",
"radial-gradient(circle closest-side at 20px 30px, red, green)");
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-corner ellipse at 20px 30px, red, green)",
"radial-gradient(ellipse closest-corner at 20px 30px, red, green)");
"radial-gradient(closest-corner at 20px 30px, red, green)");
assert_roundtrip_with_context!(Image::parse, "radial-gradient(30px circle, red, green)",
"radial-gradient(circle 30px at center center, red, green)");
"radial-gradient(30px at center center, red, green)");
assert_roundtrip_with_context!(Image::parse, "radial-gradient(30px 40px ellipse, red, green)",
"radial-gradient(ellipse 30px 40px at center center, red, green)");
"radial-gradient(30px 40px at center center, red, green)");
// Parsing without <size>
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(circle, red, green)",
"radial-gradient(circle farthest-corner at center center, red, green)");
"radial-gradient(circle at center center, red, green)");
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(ellipse, red, green)",
"radial-gradient(ellipse farthest-corner at center center, red, green)");
"radial-gradient(at center center, red, green)");
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(circle at 20px 30px, red, green)",
"radial-gradient(circle farthest-corner at 20px 30px, red, green)");
"radial-gradient(circle at 20px 30px, red, green)");
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(ellipse at 20px 30px, red, green)",
"radial-gradient(ellipse farthest-corner at 20px 30px, red, green)");
"radial-gradient(at 20px 30px, red, green)");
// Parsing without <shape-keyword>
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(20px at 20px 30px, red, green)",
"radial-gradient(circle 20px at 20px 30px, red, green)");
"radial-gradient(20px at 20px 30px, red, green)");
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(20px 30px at left center, red, green)",
"radial-gradient(ellipse 20px 30px at left center, red, green)");
"radial-gradient(20px 30px at left center, red, green)");
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(closest-side at center, red, green)",
"radial-gradient(ellipse closest-side at center center, red, green)");
"radial-gradient(closest-side at center center, red, green)");
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(20px, red, green)",
"radial-gradient(circle 20px at center center, red, green)");
"radial-gradient(20px at center center, red, green)");
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(20px 30px, red, green)",
"radial-gradient(ellipse 20px 30px at center center, red, green)");
"radial-gradient(20px 30px at center center, red, green)");
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(closest-side, red, green)",
"radial-gradient(ellipse closest-side at center center, red, green)");
"radial-gradient(closest-side at center center, red, green)");
// Parsing without <shape-keyword> and <size>
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(at center, red, green)",
"radial-gradient(ellipse farthest-corner at center center, red, green)");
"radial-gradient(at center center, red, green)");
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(at center bottom, red, green)",
"radial-gradient(ellipse farthest-corner at center bottom, red, green)");
"radial-gradient(at center bottom, red, green)");
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(at 40px 50px, red, green)",
"radial-gradient(ellipse farthest-corner at 40px 50px, red, green)");
"radial-gradient(at 40px 50px, red, green)");
// Parsing with just color stops
assert_roundtrip_with_context!(Image::parse,
"radial-gradient(red, green)",
"radial-gradient(ellipse farthest-corner at center center, red, green)");
"radial-gradient(at center center, red, green)");
// Parsing repeating radial gradient
assert_roundtrip_with_context!(Image::parse,
"repeating-radial-gradient(red, green)",
"repeating-radial-gradient(ellipse farthest-corner at center center, red, green)");
"repeating-radial-gradient(at center center, red, green)");
}

View File

@ -799,7 +799,8 @@ mod shorthand_serialization {
use style::properties::longhands::mask_position_y as position_y;
use style::properties::longhands::mask_repeat as repeat;
use style::properties::longhands::mask_size as size;
use style::values::specified::Image;
use style::values::Either;
use style::values::generics::image::Image;
use super::*;
macro_rules! single_vec_value_typedef {
@ -828,9 +829,10 @@ mod shorthand_serialization {
fn mask_should_serialize_all_available_properties_when_specified() {
let mut properties = Vec::new();
let image = single_vec_value_typedef!(image,
image::single_value::SpecifiedValue(
Some(Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))));
let image = single_vec_value_typedef!(
image,
Either::Second(Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))
);
let mode = single_vec_keyword_value!(mode, luminance);
@ -880,9 +882,10 @@ mod shorthand_serialization {
fn mask_should_combine_origin_and_clip_properties_when_equal() {
let mut properties = Vec::new();
let image = single_vec_value_typedef!(image,
image::single_value::SpecifiedValue(
Some(Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))));
let image = single_vec_value_typedef!(
image,
Either::Second(Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))
);
let mode = single_vec_keyword_value!(mode, luminance);

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cssparser::{self, Parser as CssParser, SourcePosition};
use cssparser::{self, Parser as CssParser, SourcePosition, SourceLocation};
use html5ever::{Namespace as NsAtom};
use media_queries::CSSErrorReporterTest;
use parking_lot::RwLock;
@ -82,7 +82,11 @@ fn test_parse_stylesheet() {
rules: CssRules::new(vec![
CssRule::Namespace(Arc::new(stylesheet.shared_lock.wrap(NamespaceRule {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
url: NsAtom::from("http://www.w3.org/1999/xhtml"),
source_location: SourceLocation {
line: 1,
column: 19,
},
}))),
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
@ -116,6 +120,10 @@ fn test_parse_stylesheet() {
DeclaredValueOwned::CSSWideKeyword(CSSWideKeyword::Inherit)),
Importance::Important),
]))),
source_location: SourceLocation {
line: 3,
column: 31,
},
}))),
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
@ -152,6 +160,10 @@ fn test_parse_stylesheet() {
(PropertyDeclaration::Display(longhands::display::SpecifiedValue::block),
Importance::Normal),
]))),
source_location: SourceLocation {
line: 11,
column: 27,
},
}))),
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
@ -220,6 +232,10 @@ fn test_parse_stylesheet() {
::get_initial_specified_value()])),
Importance::Normal),
]))),
source_location: SourceLocation {
line: 15,
column: 20,
},
}))),
CssRule::Keyframes(Arc::new(stylesheet.shared_lock.wrap(KeyframesRule {
name: KeyframesName::Ident(CustomIdent("foo".into())),

View File

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cssparser::SourceLocation;
use html5ever::LocalName;
use selectors::parser::LocalName as LocalNameSelector;
use selectors::parser::Selector;
@ -32,6 +33,10 @@ fn get_mock_rules(css_selectors: &[&str]) -> (Vec<Vec<Rule>>, SharedRwLock) {
longhands::display::SpecifiedValue::block),
Importance::Normal
))),
source_location: SourceLocation {
line: 0,
column: 0,
},
}));
let guard = shared_lock.read();

View File

@ -9,15 +9,13 @@
loader: taskgraph.loader.transform:loader
transforms:
- taskgraph.transforms.try_job:transforms
- taskgraph.transforms.android_stuff:transforms
- taskgraph.transforms.task:transforms
jobs:
android-api-15-gradle-dependencies:
description: "Android armv7 API 15+ gradle dependencies"
attributes:
build_platform: android-api-15-gradle-dependencies
build_type: opt
index:
product: mobile
job-name: android-api-15-gradle-dependencies-opt
@ -66,9 +64,6 @@ jobs:
android-test:
description: "Android armv7 unit tests"
attributes:
build_platform: android-test
build_type: opt
treeherder:
platform: android-4-0-armv7-api15/opt
kind: test
@ -115,9 +110,6 @@ jobs:
android-lint:
description: "Android lint"
attributes:
build_platform: android-lint
build_type: opt
treeherder:
platform: android-4-0-armv7-api15/opt
kind: test
@ -186,9 +178,6 @@ jobs:
android-checkstyle:
description: "Android checkstyle"
attributes:
build_platform: android-checkstyle
build_type: opt
treeherder:
platform: android-4-0-armv7-api15/opt
kind: test
@ -238,9 +227,6 @@ jobs:
android-findbugs:
description: "Android findbugs"
attributes:
build_platform: android-findbugs
build_type: opt
treeherder:
platform: android-4-0-armv7-api15/opt
kind: test

View File

@ -5,7 +5,7 @@
loader: taskgraph.loader.transform:loader
transforms:
- taskgraph.transforms.build_attrs:transforms
- taskgraph.transforms.try_job:transforms
- taskgraph.transforms.job:transforms
- taskgraph.transforms.task:transforms

View File

@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
linux64-clang/opt:
linux64-clang:
description: "Clang toolchain build"
treeherder:
kind: build
@ -22,7 +22,7 @@ linux64-clang/opt:
- 'build/build-clang/**'
- 'taskcluster/scripts/misc/tooltool-download.sh'
linux64-clang-tidy/opt:
linux64-clang-tidy:
description: "Clang-tidy build"
index:
product: static-analysis
@ -46,7 +46,7 @@ linux64-clang-tidy/opt:
- 'build/build-clang/**'
- 'taskcluster/scripts/misc/tooltool-download.sh'
linux64-gcc/opt:
linux64-gcc:
description: "GCC toolchain build"
treeherder:
kind: build
@ -64,7 +64,7 @@ linux64-gcc/opt:
resources:
- 'build/unix/build-gcc/**'
linux64-binutils/opt:
linux64-binutils:
description: "Binutils toolchain build"
treeherder:
kind: build
@ -82,7 +82,7 @@ linux64-binutils/opt:
resources:
- 'build/unix/build-binutils/**'
linux64-cctools-port/opt:
linux64-cctools-port:
description: "cctools-port toolchain build"
treeherder:
kind: build
@ -101,7 +101,7 @@ linux64-cctools-port/opt:
resources:
- 'taskcluster/scripts/misc/tooltool-download.sh'
linux64-hfsplus/opt:
linux64-hfsplus:
description: "hfsplus toolchain build"
treeherder:
kind: build
@ -121,7 +121,7 @@ linux64-hfsplus/opt:
- 'build/unix/build-hfsplus/**'
- 'taskcluster/scripts/misc/tooltool-download.sh'
linux64-libdmg/opt:
linux64-libdmg:
description: "libdmg-hfsplus toolchain build"
treeherder:
kind: build

View File

@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
macosx64-clang/opt:
macosx64-clang:
description: "Clang toolchain build"
treeherder:
kind: build
@ -22,7 +22,7 @@ macosx64-clang/opt:
- 'build/build-clang/**'
- 'taskcluster/scripts/misc/tooltool-download.sh'
macosx64-clang-tidy/opt:
macosx64-clang-tidy:
description: "Clang-tidy build"
index:
product: static-analysis
@ -46,7 +46,7 @@ macosx64-clang-tidy/opt:
- 'build/build-clang/**'
- 'taskcluster/scripts/misc/tooltool-download.sh'
macosx64-cctools-port/opt:
macosx64-cctools-port:
description: "cctools-port toolchain build"
treeherder:
kind: build

View File

@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
win32-clang-cl/opt:
win32-clang-cl:
description: "Clang-cl toolchain build"
treeherder:
kind: build
@ -20,7 +20,7 @@ win32-clang-cl/opt:
- 'build/build-clang/**'
- 'taskcluster/scripts/misc/build-clang-windows-helper32.sh'
win64-clang-cl/opt:
win64-clang-cl:
description: "Clang-cl toolchain build"
treeherder:
kind: build
@ -38,7 +38,7 @@ win64-clang-cl/opt:
- 'build/build-clang/**'
- 'taskcluster/scripts/misc/build-clang-windows-helper64.sh'
win32-clang-tidy/opt:
win32-clang-tidy:
description: "Clang-tidy toolchain build"
index:
product: static-analysis
@ -59,7 +59,7 @@ win32-clang-tidy/opt:
- 'build/build-clang/**'
- 'taskcluster/scripts/misc/build-clang-windows-helper32.sh'
win64-clang-tidy/opt:
win64-clang-tidy:
description: "Clang-tidy toolchain build"
index:
product: static-analysis

View File

@ -0,0 +1,19 @@
# 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/.
from __future__ import absolute_import, print_function, unicode_literals
from taskgraph.transforms.base import TransformSequence
transforms = TransformSequence()
@transforms.add
def set_job_try_name(config, jobs):
"""
For a task which is governed by `-j` in try syntax, set the `job_try_name`
attribute based on the job name.
"""
for job in jobs:
job.setdefault('attributes', {}).setdefault('job_try_name', job['name'])
yield job

View File

@ -32,12 +32,6 @@ BUILD_KINDS = set([
'spidermonkey',
])
# anything in this list is governed by -j, matching against the `build_platform` attribute
JOB_KINDS_MATCHING_BUILD_PLATFORM = set([
'toolchain',
'android-stuff',
])
# mapping from shortcut name (usable with -u) to a boolean function identifying
# matching test names
@ -595,16 +589,9 @@ class TryOptionSyntax(object):
if self.jobs is None or job_try_name in self.jobs:
if self.platforms is None or attr('build_platform') not in self.platforms:
return True
if attr('kind') == 'test':
elif attr('kind') == 'test':
return match_test(self.unittests, 'unittest_try_name') \
or match_test(self.talos, 'talos_try_name')
elif attr('kind') in JOB_KINDS_MATCHING_BUILD_PLATFORM:
# This will add 'job' tasks to the target set even if no try syntax was specified.
if not self.jobs:
return True
if attr('build_platform') in self.jobs:
return True
elif attr('kind') in BUILD_KINDS:
if attr('build_type') not in self.build_types:
return False

View File

@ -121,8 +121,8 @@ class TestSize(MarionetteTestCase):
# so reset to original size minus 1 pixel width
start_size = self.marionette.window_size
if start_size["width"] == self.max["width"] and start_size["height"] == self.max["height"]:
self.start_size["width"] -= 1
self.start_size["height"] -= 1
start_size["width"] -= 1
start_size["height"] -= 1
self.marionette.set_window_size(start_size["width"], start_size["height"])
self.original_size = self.marionette.window_size

View File

@ -1505,8 +1505,8 @@ this.PlacesUtils = {
* Your custom queries can - and will - break overtime.
*
* Example:
* let db = yield PlacesUtils.promiseDBConnection();
* let rows = yield db.executeCached(sql, params);
* let db = await PlacesUtils.promiseDBConnection();
* let rows = await db.executeCached(sql, params);
*/
promiseDBConnection: () => gAsyncDBConnPromised,
@ -1526,7 +1526,7 @@ this.PlacesUtils = {
* operations are complete before proceeding.
*
* Example:
* yield withConnectionWrapper("Bookmarks: Remove a bookmark", Task.async(function*(db) {
* await withConnectionWrapper("Bookmarks: Remove a bookmark", Task.async(function*(db) {
* // Proceed with the db, asynchronously.
* // Shutdown will not interrupt operations that take place here.
* }));
@ -2408,12 +2408,25 @@ XPCOMUtils.defineLazyGetter(this, "gKeywordsCachePromise", () =>
FROM moz_keywords k
JOIN moz_places h ON h.id = k.place_id
`);
let brokenKeywords = [];
for (let row of rows) {
let keyword = row.getResultByName("keyword");
let entry = { keyword,
url: new URL(row.getResultByName("url")),
postData: row.getResultByName("post_data") };
cache.set(keyword, entry);
try {
let entry = { keyword,
url: new URL(row.getResultByName("url")),
postData: row.getResultByName("post_data") };
cache.set(keyword, entry);
} catch (ex) {
// The url is invalid, don't load the keyword and remove it, or it
// would break the whole keywords API.
brokenKeywords.push(keyword);
}
}
if (brokenKeywords.length) {
await db.execute(
`DELETE FROM moz_keywords
WHERE keyword IN (${brokenKeywords.map(JSON.stringify).join(",")})
`);
}
// Helper to get a keyword from an href.

View File

@ -19,7 +19,11 @@ async function check_keyword(aExpectExists, aHref, aKeyword, aPostData = null) {
} else {
Assert.ok(!entry || entry.url.href != aHref,
"The given keyword entry should not exist");
Assert.equal(null, await PlacesUtils.keywords.fetch({ keyword: aKeyword, url: aHref }));
if (aHref) {
Assert.equal(null, await PlacesUtils.keywords.fetch({ keyword: aKeyword, url: aHref }));
} else {
Assert.equal(null, await PlacesUtils.keywords.fetch({ keyword: aKeyword }));
}
}
}
@ -79,6 +83,30 @@ function expectBookmarkNotifications() {
return observer;
}
// This test must be the first one, since it creates the keywords cache.
add_task(async function test_invalidURL() {
await PlacesTestUtils.addVisits("http://test.com/");
// Change to url to an invalid one, there's no API for that, so we must do
// that manually.
await PlacesUtils.withConnectionWrapper("test_invalidURL", async function(db) {
await db.execute(
`UPDATE moz_places SET url = :broken, url_hash = hash(:broken)
WHERE id = (SELECT id FROM moz_places WHERE url_hash = hash(:url))`,
{ url: "http://test.com/", broken: "<invalid url>" });
await db.execute(
`INSERT INTO moz_keywords (keyword, place_id)
VALUES (:kw, (SELECT id FROM moz_places WHERE url_hash = hash(:broken)))`,
{ broken: "<invalid url>", kw: "keyword" });
});
await check_keyword(false, "http://broken.com/", "keyword");
await check_keyword(false, null, "keyword");
await PlacesUtils.withConnectionWrapper("test_invalidURL", async function(db) {
let rows = await db.execute(`SELECT * FROM moz_keywords`);
Assert.equal(rows.length, 0, "The broken keyword should have been removed");
});
});
add_task(async function test_invalid_input() {
Assert.throws(() => PlacesUtils.keywords.fetch(null),
/Invalid keyword/);
@ -174,7 +202,6 @@ add_task(async function test_addBookmarkAndKeyword() {
await check_keyword(false, "http://example.com/", "keyword");
let fc = await foreign_count("http://example.com/");
let bookmark = await PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
let observer = expectBookmarkNotifications();
@ -270,7 +297,6 @@ add_task(async function test_addBookmarkToURIHavingKeyword() {
observer = expectBookmarkNotifications();
let bookmark = await PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
Assert.equal((await foreign_count("http://example.com/")), fc + 2); // +1 bookmark
observer.check([]);
@ -292,11 +318,9 @@ add_task(async function test_addBookmarkToURIHavingKeyword() {
add_task(async function test_sameKeywordDifferentURL() {
let fc1 = await foreign_count("http://example1.com/");
let bookmark1 = await PlacesUtils.bookmarks.insert({ url: "http://example1.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
let fc2 = await foreign_count("http://example2.com/");
let bookmark2 = await PlacesUtils.bookmarks.insert({ url: "http://example2.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
await PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example1.com/" });
@ -358,7 +382,6 @@ add_task(async function test_sameURIDifferentKeyword() {
let observer = expectBookmarkNotifications();
let bookmark = await PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
await PlacesUtils.keywords.insert({keyword: "keyword", url: "http://example.com/" });
@ -423,10 +446,8 @@ add_task(async function test_deleteKeywordMultipleBookmarks() {
let observer = expectBookmarkNotifications();
let bookmark1 = await PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
let bookmark2 = await PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
await PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com/" });
@ -489,7 +510,6 @@ add_task(async function test_multipleKeywordsSamePostData() {
add_task(async function test_oldPostDataAPI() {
let bookmark = await PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
await PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com/" });
let itemId = await PlacesUtils.promiseItemId(bookmark.guid);
@ -505,7 +525,6 @@ add_task(async function test_oldPostDataAPI() {
add_task(async function test_oldKeywordsAPI() {
let bookmark = await PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
await check_keyword(false, "http://example.com/", "keyword");
let itemId = await PlacesUtils.promiseItemId(bookmark.guid);
@ -532,7 +551,6 @@ add_task(async function test_bookmarkURLChange() {
let fc1 = await foreign_count("http://example1.com/");
let fc2 = await foreign_count("http://example2.com/");
let bookmark = await PlacesUtils.bookmarks.insert({ url: "http://example1.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
await PlacesUtils.keywords.insert({ keyword: "keyword",
url: "http://example1.com/" });

View File

@ -0,0 +1,8 @@
"use strict";
module.exports = {
"rules": {
// Require object keys to be sorted.
"sort-keys": "error"
}
};

View File

@ -2,12 +2,6 @@
"use strict";
module.exports = {
"rules": {
"mozilla/import-content-task-globals": "error",
"mozilla/import-headjs-globals": "warn",
"mozilla/mark-test-function-used": "warn"
},
"env": {
"browser": true,
"mozilla/browser-window": true,
@ -15,52 +9,58 @@ module.exports = {
// "node": true
},
"plugins": [
"mozilla"
],
// All globals made available in the test environment.
"globals": {
// `$` is defined in SimpleTest.js
"$": false,
"add_task": false,
"addLoadEvent": false,
"Assert": false,
"BrowserTestUtils": false,
"content": false,
"ContentTask": false,
"ContentTaskUtils": false,
"EventUtils": false,
"PromiseDebugging": false,
"SpecialPowers": false,
"TestUtils": false,
"XPCNativeWrapper": false,
"XULDocument": false,
"addLoadEvent": false,
"add_task": false,
"content": false,
"executeSoon": false,
"expectUncaughtException": false,
"export_assertions": false,
"extractJarToTmp": false,
"finish": false,
"gTestPath": false,
"getChromeDir": false,
"getJar": false,
"getResolvedURI": false,
"getRootDirectory": false,
"getTestFilePath": false,
"gTestPath": false,
"info": false,
"ignoreAllUncaughtExceptions": false,
"info": false,
"is": false,
"isnot": false,
"ok": false,
"PromiseDebugging": false,
"privateNoteIntentionalCrash": false,
"registerCleanupFunction": false,
"requestLongerTimeout": false,
"SpecialPowers": false,
"TestUtils": false,
"thisTestLeaksUncaughtRejectionsAndShouldBeFixed": false,
"todo": false,
"todo_is": false,
"todo_isnot": false,
"waitForClipboard": false,
"waitForExplicitFinish": false,
"waitForFocus": false,
"XPCNativeWrapper": false,
"XULDocument": false
"waitForFocus": false
},
"plugins": [
"mozilla"
],
"rules": {
"mozilla/import-content-task-globals": "error",
"mozilla/import-headjs-globals": "warn",
"mozilla/mark-test-function-used": "warn"
}
};

Some files were not shown because too many files have changed in this diff Show More