merge autoland to mozilla-central. r=merge a=merge

MozReview-Commit-ID: CdkzY7WJ58G
This commit is contained in:
Sebastian Hengst 2017-10-10 23:48:17 +02:00
Родитель c8b9469182 3a90ea2602
Коммит 7b58b734df
339 изменённых файлов: 5153 добавлений и 3249 удалений

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

@ -560,7 +560,7 @@ var gPluginHandler = {
// Configure the notification bar
let priority = notificationBox.PRIORITY_WARNING_MEDIUM;
let iconURL = "chrome://mozapps/skin/plugins/notifyPluginCrashed.png";
let iconURL = "chrome://mozapps/skin/plugins/pluginGeneric.svg";
let reloadLabel = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.label");
let reloadKey = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.accesskey");

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

@ -154,8 +154,6 @@ var whitelist = [
// Bug 1348533
{file: "chrome://mozapps/skin/downloads/buttons.png", platforms: ["macosx"]},
{file: "chrome://mozapps/skin/downloads/downloadButtons.png", platforms: ["linux", "win"]},
// Bug 1348556
{file: "chrome://mozapps/skin/plugins/pluginBlocked.png"},
// Bug 1348558
{file: "chrome://mozapps/skin/update/downloadButtons.png",
platforms: ["linux"]},

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

@ -123,7 +123,6 @@ class BasePopup {
if (this.viewNode) {
this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
this.viewNode.style.maxHeight = "";
delete this.viewNode.customRectGetter;
}
@ -331,16 +330,9 @@ class BasePopup {
height = Math.min(height, maxHeight);
this.browser.style.height = `${height}px`;
// Set a maximum height on the <panelview> element to our preferred
// maximum height, so that the PanelUI resizing code can make an accurate
// calculation. If we don't do this, the flex sizing logic will prevent us
// from ever reporting a preferred size smaller than the height currently
// available to us in the panel.
height = Math.max(height, this.viewHeight);
this.viewNode.style.maxHeight = `${height}px`;
// Used by the panelmultiview code to figure out sizing without reparenting
// (which would destroy the browser and break us).
this.lastCalculatedInViewHeight = height;
this.lastCalculatedInViewHeight = Math.max(height, this.viewHeight);
} else {
this.browser.style.width = `${width}px`;
this.browser.style.minWidth = `${width}px`;

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

@ -88,7 +88,6 @@ class ParentDevToolsPanel {
icon: icon,
label: title,
tooltip: `DevTools Panel added by "${extensionName}" add-on.`,
invertIconForLightTheme: false,
visibilityswitch: `devtools.webext-${this.id}.enabled`,
isTargetSupported: target => target.isLocalTab,
build: (window, toolbox) => {

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

@ -214,9 +214,6 @@ add_task(async function test_devtools_page_panels_create() {
const panelDef = toolboxAdditionalTools[0];
const panelId = panelDef.id;
is(panelDef.invertIconForLightTheme, false,
"devtools.panel.create set invertIconForLightTheme to false by default");
await gDevTools.showToolbox(target, panelId);
const {devtoolsPageTabId} = await extension.awaitMessage("devtools_panel_shown");
const devtoolsPanelTabId = await extension.awaitMessage("devtools_panel_inspectedWindow_tabId");

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

@ -120,12 +120,6 @@ add_task(async function tests() {
let engine = Services.search.getEngineByName("Google");
ok(engine, "Google");
// Show the search bar after initializing the search service, to avoid the
// synchronous initialization to interfere.
await SpecialPowers.pushPrefEnv({ set: [
["browser.search.widget.inNavBar", true],
]});
let base = "https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8&client=firefox-b";
// Keyword uses a slightly different code

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

@ -120,12 +120,6 @@ add_task(async function tests() {
let engine = Services.search.getEngineByName("Google");
ok(engine, "Google");
// Show the search bar after initializing the search service, to avoid the
// synchronous initialization to interfere.
await SpecialPowers.pushPrefEnv({ set: [
["browser.search.widget.inNavBar", true],
]});
let base = "https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8";
let url;

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

@ -858,7 +858,11 @@ Function createInstall
${ITBL3Create}
${ITBL3SetProgressState} "${TBPF_INDETERMINATE}"
; Make sure the file we're about to try to download to doesn't already exist,
; so we don't end up trying to "resume" on top of the wrong file.
Delete "$PLUGINSDIR\download.exe"
${NSD_CreateTimer} StartDownload ${DownloadIntervalMS}
${NSD_CreateTimer} ClearBlurb ${BlurbDisplayMS}
LockWindow off
@ -931,12 +935,24 @@ Function OnDownload
# $2 = Remaining files
# $3 = Number of downloaded bytes for the current file
# $4 = Size of current file (Empty string if the size is unknown)
# /RESET must be used if status $0 > 299 (e.g. failure)
# /RESET must be used if status $0 > 299 (e.g. failure), even if resuming
# When status is $0 =< 299 it is handled by InetBgDL
StrCpy $DownloadServerIP "$5"
${If} $0 > 299
${NSD_KillTimer} OnDownload
IntOp $DownloadRetryCount $DownloadRetryCount + 1
${If} $DownloadRetryCount >= ${DownloadMaxRetries}
StrCpy $ExitCode "${ERR_DOWNLOAD_TOO_MANY_RETRIES}"
; Use a timer so the UI has a chance to update
${NSD_CreateTimer} DisplayDownloadError ${InstallIntervalMS}
Return
${EndIf}
; 1000 is a special code meaning InetBgDL lost the connection before it got
; all the bytes it was expecting. We'll try to resume the transfer in that
; case (assuming we aren't out of retries), so don't treat it as a reset
; or clear the progress bar.
${If} $0 != 1000
${If} "$DownloadReset" != "true"
StrCpy $DownloadedBytes "0"
${NSD_AddStyle} $Progressbar ${PBS_MARQUEE}
@ -944,17 +960,13 @@ Function OnDownload
$ProgressbarMarqueeIntervalMS ; start=1|stop=0 interval(ms)=+N
${ITBL3SetProgressState} "${TBPF_INDETERMINATE}"
${EndIf}
InetBgDL::Get /RESET /END
StrCpy $DownloadSizeBytes ""
StrCpy $DownloadReset "true"
${If} $DownloadRetryCount >= ${DownloadMaxRetries}
StrCpy $ExitCode "${ERR_DOWNLOAD_TOO_MANY_RETRIES}"
; Use a timer so the UI has a chance to update
${NSD_CreateTimer} DisplayDownloadError ${InstallIntervalMS}
${Else}
${NSD_CreateTimer} StartDownload ${DownloadRetryIntervalMS}
Delete "$PLUGINSDIR\download.exe"
${EndIf}
InetBgDL::Get /RESET /END
${NSD_CreateTimer} StartDownload ${DownloadRetryIntervalMS}
Return
${EndIf}

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

@ -90,6 +90,16 @@ var AttributionCode = {
})();
},
/**
* Return the cached attribution data synchronously without hitting
* the disk.
* @returns A dictionary with the attribution data if it's available,
* null otherwise.
*/
getCachedAttributionData() {
return gCachedAttrData;
},
/**
* Deletes the attribution data file.
* Returns a promise that resolves when the file is deleted,

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

@ -47,7 +47,7 @@ menuitem[appHandlerIcon="feed"] {
richlistitem[appHandlerIcon="plugin"],
menuitem[appHandlerIcon="plugin"] {
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png");
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.svg");
}
.actionsMenu .menulist-icon {

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

@ -58,7 +58,7 @@ menuitem[appHandlerIcon="feed"] {
richlistitem[appHandlerIcon="plugin"],
menuitem[appHandlerIcon="plugin"] {
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png");
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.svg");
}
/* Repeat what menu.css does for .menuitem-iconic */

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

@ -205,7 +205,7 @@ html|*#webRTC-previewVideo {
}
.popup-notification-icon[popupid="click-to-play-plugins"] {
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked.svg);
}
/* OFFLINE APPS */

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

@ -402,6 +402,11 @@
height: 11px;
}
.searchbar-search-button[addengines=true] > .searchbar-search-icon-overlay:-moz-locale-dir(rtl) {
margin-inline-start: -25px;
margin-inline-end: 14px;
}
.searchbar-search-button:hover:not([addengines=true]) > .searchbar-search-icon-overlay {
list-style-image: url(chrome://global/skin/icons/arrow-dropdown-12.svg);
-moz-context-properties: fill;
@ -410,3 +415,8 @@
width: 6px;
height: 6px;
}
.searchbar-search-button:hover:not([addengines=true]) > .searchbar-search-icon-overlay:-moz-locale-dir(rtl) {
margin-inline-start: -26px;
margin-inline-end: 20px;
}

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

@ -47,7 +47,7 @@ menuitem[appHandlerIcon="feed"] {
richlistitem[appHandlerIcon="plugin"],
menuitem[appHandlerIcon="plugin"] {
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png");
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.svg");
}
.actionsMenu .menulist-icon {

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

@ -316,6 +316,7 @@ for version in $4; do
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $ANDROID_SDK_ROOT/tools/lib/repository-$version.jar"
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $ANDROID_SDK_ROOT/tools/lib/common-$version.jar"
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $ANDROID_SDK_ROOT/tools/lib/lint-api-$version.jar"
ANDROID_LINT_CLASSPATH="$ANDROID_LINT_CLASSPATH $ANDROID_SDK_ROOT/tools/lib/manifest-merger-$version.jar"
break
fi
done

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

@ -76,7 +76,6 @@ function setPrefDefaults() {
// Bug 1225160 - Using source maps with browser debugging can lead to a crash
Services.prefs.setBoolPref("devtools.debugger.source-maps-enabled", false);
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", true);
Services.prefs.setBoolPref("devtools.debugger.client-source-maps-enabled", true);
Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", false);
}
window.addEventListener("load", function () {

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

@ -20,6 +20,7 @@ const TEST_URI = `
background: none;
transition: initial;
z-index: 0;
opacity: 1;
}
</style>
<div id="test"></div>
@ -39,6 +40,7 @@ add_task(function* () {
yield testShorthandIncrements(view);
yield testOddCases(view);
yield testZeroValueIncrements(view);
yield testOpacityIncrements(view);
});
function* testMarginIncrements(view) {
@ -227,7 +229,29 @@ function* testZeroValueIncrements(view) {
});
}
function* testOpacityIncrements(view) {
info("Testing keyboard increments on the opacity property");
let idRuleEditor = getRuleViewRuleEditor(view, 1);
let opacityPropEditor = idRuleEditor.rule.textProps[7].editor;
yield runIncrementTest(opacityPropEditor, view, {
1: {alt: true, start: "0.5", end: "0.51", selectAll: true},
2: {start: "0", end: "0.1", selectAll: true},
3: {shift: true, start: "0", end: "1", selectAll: true},
4: {down: true, alt: true, start: "0.1", end: "0.09", selectAll: true},
5: {down: true, start: "0", end: "-0.1", selectAll: true},
6: {down: true, shift: true, start: "0", end: "-1", selectAll: true},
7: {pageUp: true, shift: true, start: "0", end: "10", selectAll: true},
8: {pageDown: true, shift: true, start: "0", end: "-10",
selectAll: true},
9: {start: "0.7", end: "0.8", selectAll: true},
10: {down: true, start: "0", end: "-0.1", selectAll: true},
});
}
function* runIncrementTest(propertyEditor, view, tests) {
propertyEditor.valueSpan.scrollIntoView();
let editor = yield focusEditableField(view, propertyEditor.valueSpan);
for (let test in tests) {

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

@ -295,6 +295,7 @@ TextPropertyEditor.prototype = {
advanceChars: advanceValidate,
contentType: InplaceEditor.CONTENT_TYPES.CSS_VALUE,
property: this.prop,
defaultIncrement: this.prop.name === "opacity" ? 0.1 : 1,
popup: this.popup,
multiline: true,
maxWidth: () => this.container.getBoundingClientRect().width,

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

@ -45,10 +45,10 @@ const {
} = require("./actions/snapshot");
const { changeViewAndRefresh, popViewAndRefresh } = require("./actions/view");
const { resizeShortestPaths } = require("./actions/sizes");
const Toolbar = createFactory(require("./components/toolbar"));
const List = createFactory(require("./components/list"));
const SnapshotListItem = createFactory(require("./components/snapshot-list-item"));
const Heap = createFactory(require("./components/heap"));
const Toolbar = createFactory(require("./components/Toolbar"));
const List = createFactory(require("./components/List"));
const SnapshotListItem = createFactory(require("./components/SnapshotListItem"));
const Heap = createFactory(require("./components/Heap"));
const { app: appModel } = require("./models");
const MemoryApp = createClass({

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

@ -6,7 +6,7 @@
const { createClass, PropTypes, createFactory } = require("devtools/client/shared/vendor/react");
const Tree = createFactory(require("devtools/client/shared/components/Tree"));
const CensusTreeItem = createFactory(require("./census-tree-item"));
const CensusTreeItem = createFactory(require("./CensusTreeItem"));
const { TREE_ROW_HEIGHT } = require("../constants");
const { censusModel, diffingModel } = require("../models");

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

@ -8,7 +8,7 @@ const { DOM: dom, createClass, PropTypes, createFactory } = require("devtools/cl
const { assert } = require("devtools/shared/DevToolsUtils");
const { createParentMap } = require("devtools/shared/heapsnapshot/CensusUtils");
const Tree = createFactory(require("devtools/client/shared/components/Tree"));
const DominatorTreeItem = createFactory(require("./dominator-tree-item"));
const DominatorTreeItem = createFactory(require("./DominatorTreeItem"));
const { L10N } = require("../utils");
const { TREE_ROW_HEIGHT, dominatorTreeState } = require("../constants");
const { dominatorTreeModel } = require("../models");

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

@ -6,15 +6,15 @@
const { DOM: dom, createClass, PropTypes, createFactory } = require("devtools/client/shared/vendor/react");
const { assert, safeErrorString } = require("devtools/shared/DevToolsUtils");
const Census = createFactory(require("./census"));
const CensusHeader = createFactory(require("./census-header"));
const DominatorTree = createFactory(require("./dominator-tree"));
const DominatorTreeHeader = createFactory(require("./dominator-tree-header"));
const TreeMap = createFactory(require("./tree-map"));
const Census = createFactory(require("./Census"));
const CensusHeader = createFactory(require("./CensusHeader"));
const DominatorTree = createFactory(require("./DominatorTree"));
const DominatorTreeHeader = createFactory(require("./DominatorTreeHeader"));
const TreeMap = createFactory(require("./TreeMap"));
const HSplitBox = createFactory(require("devtools/client/shared/components/HSplitBox"));
const Individuals = createFactory(require("./individuals"));
const IndividualsHeader = createFactory(require("./individuals-header"));
const ShortestPaths = createFactory(require("./shortest-paths"));
const Individuals = createFactory(require("./Individuals"));
const IndividualsHeader = createFactory(require("./IndividualsHeader"));
const ShortestPaths = createFactory(require("./ShortestPaths"));
const { getStatusTextFull, L10N } = require("../utils");
const {
snapshotState: states,

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

@ -6,7 +6,7 @@
const { createClass, PropTypes, createFactory } = require("devtools/client/shared/vendor/react");
const Tree = createFactory(require("devtools/client/shared/components/Tree"));
const DominatorTreeItem = createFactory(require("./dominator-tree-item"));
const DominatorTreeItem = createFactory(require("./DominatorTreeItem"));
const { TREE_ROW_HEIGHT } = require("../constants");
const models = require("../models");

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

@ -8,18 +8,18 @@ DIRS += [
]
DevToolsModules(
'census-header.js',
'census-tree-item.js',
'census.js',
'dominator-tree-header.js',
'dominator-tree-item.js',
'dominator-tree.js',
'heap.js',
'individuals-header.js',
'individuals.js',
'list.js',
'shortest-paths.js',
'snapshot-list-item.js',
'toolbar.js',
'tree-map.js',
'Census.js',
'CensusHeader.js',
'CensusTreeItem.js',
'DominatorTree.js',
'DominatorTreeHeader.js',
'DominatorTreeItem.js',
'Heap.js',
'Individuals.js',
'IndividualsHeader.js',
'List.js',
'ShortestPaths.js',
'SnapshotListItem.js',
'Toolbar.js',
'TreeMap.js',
)

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

@ -49,15 +49,15 @@ var models = require("devtools/client/memory/models");
var Immutable = require("devtools/client/shared/vendor/immutable");
var React = require("devtools/client/shared/vendor/react");
var ReactDOM = require("devtools/client/shared/vendor/react-dom");
var Heap = React.createFactory(require("devtools/client/memory/components/heap"));
var CensusTreeItem = React.createFactory(require("devtools/client/memory/components/census-tree-item"));
var DominatorTreeComponent = React.createFactory(require("devtools/client/memory/components/dominator-tree"));
var DominatorTreeItem = React.createFactory(require("devtools/client/memory/components/dominator-tree-item"));
var ShortestPaths = React.createFactory(require("devtools/client/memory/components/shortest-paths"));
var TreeMap = React.createFactory(require("devtools/client/memory/components/tree-map"));
var SnapshotListItem = React.createFactory(require("devtools/client/memory/components/snapshot-list-item"));
var List = React.createFactory(require("devtools/client/memory/components/list"));
var Toolbar = React.createFactory(require("devtools/client/memory/components/toolbar"));
var Heap = React.createFactory(require("devtools/client/memory/components/Heap"));
var CensusTreeItem = React.createFactory(require("devtools/client/memory/components/CensusTreeItem"));
var DominatorTreeComponent = React.createFactory(require("devtools/client/memory/components/DominatorTree"));
var DominatorTreeItem = React.createFactory(require("devtools/client/memory/components/DominatorTreeItem"));
var ShortestPaths = React.createFactory(require("devtools/client/memory/components/ShortestPaths"));
var TreeMap = React.createFactory(require("devtools/client/memory/components/TreeMap"));
var SnapshotListItem = React.createFactory(require("devtools/client/memory/components/SnapshotListItem"));
var List = React.createFactory(require("devtools/client/memory/components/List"));
var Toolbar = React.createFactory(require("devtools/client/memory/components/Toolbar"));
// All tests are asynchronous.
SimpleTest.waitForExplicitFinish();

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

@ -27,9 +27,9 @@ const {
resizeViewport,
rotateViewport,
} = require("./actions/viewports");
const DeviceModal = createFactory(require("./components/device-modal"));
const GlobalToolbar = createFactory(require("./components/global-toolbar"));
const Viewports = createFactory(require("./components/viewports"));
const DeviceModal = createFactory(require("./components/DeviceModal"));
const GlobalToolbar = createFactory(require("./components/GlobalToolbar"));
const Viewports = createFactory(require("./components/Viewports"));
const Types = require("./types");
let App = createClass({

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

@ -11,7 +11,7 @@ const { DOM: dom, createClass, createFactory, PropTypes, addons } =
const { getFormatStr, getStr } = require("../utils/l10n");
const Types = require("../types");
const ViewportDimension = createFactory(require("./viewport-dimension"));
const ViewportDimension = createFactory(require("./ViewportDimension.js"));
module.exports = createClass({
displayName: "DeviceAdder",

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

@ -11,7 +11,7 @@ const { DOM: dom, createClass, createFactory, PropTypes, addons } =
const { getStr, getFormatStr } = require("../utils/l10n");
const Types = require("../types");
const DeviceAdder = createFactory(require("./device-adder"));
const DeviceAdder = createFactory(require("./DeviceAdder"));
module.exports = createClass({
displayName: "DeviceModal",

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

@ -9,8 +9,8 @@ const { DOM: dom, createClass, createFactory, PropTypes, addons } =
const { getStr } = require("../utils/l10n");
const Types = require("../types");
const DPRSelector = createFactory(require("./dpr-selector"));
const NetworkThrottlingSelector = createFactory(require("./network-throttling-selector"));
const DPRSelector = createFactory(require("./DprSelector"));
const NetworkThrottlingSelector = createFactory(require("./NetworkThrottlingSelector"));
module.exports = createClass({
displayName: "GlobalToolbar",

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

@ -11,8 +11,8 @@ const { DOM: dom, createClass, createFactory, PropTypes } =
const Constants = require("../constants");
const Types = require("../types");
const Browser = createFactory(require("./browser"));
const ViewportToolbar = createFactory(require("./viewport-toolbar"));
const Browser = createFactory(require("./Browser"));
const ViewportToolbar = createFactory(require("./ViewportToolbar"));
const VIEWPORT_MIN_WIDTH = Constants.MIN_VIEWPORT_DIMENSION;
const VIEWPORT_MIN_HEIGHT = Constants.MIN_VIEWPORT_DIMENSION;

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

@ -8,8 +8,8 @@ const { DOM: dom, createClass, createFactory, PropTypes } =
require("devtools/client/shared/vendor/react");
const Types = require("../types");
const ResizableViewport = createFactory(require("./resizable-viewport"));
const ViewportDimension = createFactory(require("./viewport-dimension"));
const ResizableViewport = createFactory(require("./ResizableViewport"));
const ViewportDimension = createFactory(require("./ViewportDimension"));
module.exports = createClass({

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

@ -9,7 +9,7 @@ const { DOM: dom, createClass, createFactory, PropTypes, addons } =
const { getStr } = require("../utils/l10n");
const Types = require("../types");
const DeviceSelector = createFactory(require("./device-selector"));
const DeviceSelector = createFactory(require("./DeviceSelector"));
module.exports = createClass({
displayName: "ViewportToolbar",

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

@ -8,7 +8,7 @@ const { DOM: dom, createClass, createFactory, PropTypes } =
require("devtools/client/shared/vendor/react");
const Types = require("../types");
const Viewport = createFactory(require("./viewport"));
const Viewport = createFactory(require("./Viewport"));
module.exports = createClass({

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

@ -5,16 +5,16 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'browser.js',
'device-adder.js',
'device-modal.js',
'device-selector.js',
'dpr-selector.js',
'global-toolbar.js',
'network-throttling-selector.js',
'resizable-viewport.js',
'viewport-dimension.js',
'viewport-toolbar.js',
'viewport.js',
'viewports.js',
'Browser.js',
'DeviceAdder.js',
'DeviceModal.js',
'DeviceSelector.js',
'DprSelector.js',
'GlobalToolbar.js',
'NetworkThrottlingSelector.js',
'ResizableViewport.js',
'Viewport.js',
'ViewportDimension.js',
'Viewports.js',
'ViewportToolbar.js',
)

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

@ -122,6 +122,8 @@ function isKeyIn(key, ...keys) {
* from `element` to the new input.
* defaults to false
* {Object} cssProperties: An instance of CSSProperties.
* {Number} defaultIncrement: The value by which the input is incremented
* or decremented by default (0.1 for properties like opacity and 1 by default)
*/
function editableField(options) {
return editableItem(options, function (element, event) {
@ -225,6 +227,7 @@ function InplaceEditor(options, event) {
this.change = options.change;
this.done = options.done;
this.contextMenu = options.contextMenu;
this.defaultIncrement = options.defaultIncrement || 1;
this.destroy = options.destroy;
this.initial = options.initial ? options.initial : this.elt.textContent;
this.multiline = options.multiline || false;
@ -1209,9 +1212,9 @@ InplaceEditor.prototype = {
let key = event.keyCode;
if (isKeyIn(key, "UP", "PAGE_UP")) {
increment = 1;
increment = 1 * this.defaultIncrement;
} else if (isKeyIn(key, "DOWN", "PAGE_DOWN")) {
increment = -1;
increment = -1 * this.defaultIncrement;
}
if (event.shiftKey && !event.altKey) {

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

@ -34,7 +34,7 @@ html, body, #app, #memory-tool {
--sidebar-width: 185px;
/**
* If --heap-tree-row-height changes, be sure to change HEAP_TREE_ROW_HEIGHT
* in `devtools/client/memory/components/heap.js`.
* in `devtools/client/memory/components/Heap.js`.
*/
--heap-tree-row-height: 18px;
--heap-tree-header-height: 18px;

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

@ -173,19 +173,16 @@ li.error > .stylesheet-info > .stylesheet-more > .stylesheet-error-message {
background-size: 16px;
width: 24px;
height: 40px;
/* The icon color should always match the text color. */
-moz-context-properties: fill;
fill: var(--theme-toolbar-color);
fill: currentColor;
}
.disabled > .stylesheet-enabled {
opacity: 0.3;
}
/* Invert the toggle icon in the active row for light theme */
.splitview-nav > li.splitview-active .stylesheet-enabled {
fill: var(--theme-toolbar-selected-color);
}
.splitview-nav > li > .stylesheet-enabled:focus,
.splitview-nav > li:hover > .stylesheet-enabled {
outline: 0;

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

@ -152,10 +152,6 @@
background-color: var(--theme-toolbar-hover-active);
}
.devtools-tab:not(.selected).highlighted {
background-color: var(--theme-toolbar-background-alt);
}
.devtools-tab.selected {
color: var(--theme-toolbar-selected-color);
}

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

@ -27,7 +27,7 @@
--theme-toolbar-color: var(--grey-90);
--theme-toolbar-selected-color: var(--blue-60);
--theme-toolbar-checked-color: var(--blue-60);
--theme-toolbar-highlighted-color: #5FC749;
--theme-toolbar-highlighted-color: var(--green-60);
--theme-toolbar-background-hover: rgba(221, 225, 228, 0.66);
--theme-toolbar-background-alt: #f5f5f5;
--theme-toolbar-hover: var(--grey-20);
@ -112,7 +112,7 @@
--theme-toolbar-color: var(--grey-40);
--theme-toolbar-selected-color: white;
--theme-toolbar-checked-color: #75BFFF;
--theme-toolbar-highlighted-color: #5FC749;
--theme-toolbar-highlighted-color: var(--green-50);
--theme-toolbar-background-hover: #20232B;
--theme-toolbar-background-alt: #2F343E;
--theme-toolbar-hover: #252526;
@ -298,6 +298,8 @@
--red-70: #a4000f;
--green-50: #30e60b;
--green-60: #12bc00;
--green-70: #058b00;
--yellow-80: #715100;

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

@ -23,12 +23,12 @@ stubPreparedMessages.set("Unknown property such-unknown-property. Declara
"level": "warn",
"messageText": "Unknown property such-unknown-property. Declaration dropped.",
"parameters": null,
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html\",\"line\":3,\"column\":3},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Unknown property such-unknown-property. Declaration dropped.\",\"parameters\":null,\"source\":\"css\",\"type\":\"log\",\"userProvidedStyles\":null}",
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html\",\"line\":3,\"column\":25},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Unknown property such-unknown-property. Declaration dropped.\",\"parameters\":null,\"source\":\"css\",\"type\":\"log\",\"userProvidedStyles\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html",
"line": 3,
"column": 3
"column": 25
},
"groupId": null,
"userProvidedStyles": null,
@ -46,12 +46,12 @@ stubPreparedMessages.set("Error in parsing value for padding-top. Declara
"level": "warn",
"messageText": "Error in parsing value for padding-top. Declaration dropped.",
"parameters": null,
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html\",\"line\":3,\"column\":3},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Error in parsing value for padding-top. Declaration dropped.\",\"parameters\":null,\"source\":\"css\",\"type\":\"log\",\"userProvidedStyles\":null}",
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html\",\"line\":3,\"column\":16},\"groupId\":null,\"indent\":0,\"level\":\"warn\",\"messageText\":\"Error in parsing value for padding-top. Declaration dropped.\",\"parameters\":null,\"source\":\"css\",\"type\":\"log\",\"userProvidedStyles\":null}",
"stacktrace": null,
"frame": {
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html",
"line": 3,
"column": 3
"column": 16
},
"groupId": null,
"userProvidedStyles": null,
@ -68,7 +68,7 @@ stubPackets.set("Unknown property such-unknown-property. Declaration drop
"sourceName": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html",
"lineText": "",
"lineNumber": 3,
"columnNumber": 3,
"columnNumber": 25,
"category": "CSS Parser",
"timeStamp": 1479159920406,
"warning": true,
@ -91,7 +91,7 @@ stubPackets.set("Error in parsing value for padding-top. Declaration drop
"sourceName": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html",
"lineText": "",
"lineNumber": 3,
"columnNumber": 3,
"columnNumber": 16,
"category": "CSS Parser",
"timeStamp": 1479159920465,
"warning": true,

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

@ -36,11 +36,7 @@ const CONTAINER_FLASHING_DURATION = 500;
*/
const filenameParam = {
name: "filename",
type: {
name: "file",
filetype: "file",
existing: "maybe",
},
type: "string",
defaultValue: FILENAME_DEFAULT_VALUE,
description: l10n.lookup("screenshotFilenameDesc"),
manual: l10n.lookup("screenshotFilenameManual")

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

@ -329,6 +329,28 @@ public:
mAncestorPrincipals = mozilla::Move(aAncestorPrincipals);
}
/**
* Get the list of ancestor outerWindowIDs for this docshell. The list is meant
* to be the list of outer window IDs that correspond to the ancestorPrincipals
* above. For each ancestor principal, we store the parent window ID.
*/
const nsTArray<uint64_t>& AncestorOuterWindowIDs() const
{
return mAncestorOuterWindowIDs;
}
/**
* Set the list of ancestor outer window IDs for this docshell. We call this
* from frameloader as well in order to keep the array matched with the
* ancestor principals.
*
* This method steals the data from the passed-in array.
*/
void SetAncestorOuterWindowIDs(nsTArray<uint64_t>&& aAncestorOuterWindowIDs)
{
mAncestorOuterWindowIDs = mozilla::Move(aAncestorOuterWindowIDs);
}
private:
bool CanSetOriginAttributes();
@ -1135,6 +1157,8 @@ private:
// Our list of ancestor principals.
nsTArray<nsCOMPtr<nsIPrincipal>> mAncestorPrincipals;
// Our list of ancestor outerWindowIDs.
nsTArray<uint64_t> mAncestorOuterWindowIDs;
// Separate function to do the actual name (i.e. not _top, _self etc.)
// searching for FindItemWithName.

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

@ -4995,6 +4995,7 @@ nsIDocument::SetContainer(nsDocShell* aContainer)
}
mAncestorPrincipals = aContainer->AncestorPrincipals();
mAncestorOuterWindowIDs = aContainer->AncestorOuterWindowIDs();
}
nsISupports*

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

@ -2494,7 +2494,11 @@ nsFrameLoader::MaybeCreateDocShell()
MOZ_RELEASE_ASSERT(!doc->IsResourceDoc(), "We shouldn't even exist");
if (!(doc->IsStaticDocument() || mOwnerContent->IsInComposedDoc())) {
// Check if the document still has a window since it is possible for an
// iframe to be inserted and cause the creation of the docshell in a
// partially unloaded document (see Bug 1305237 comment 127).
if (!doc->IsStaticDocument() &&
(!doc->GetWindow() || !mOwnerContent->IsInComposedDoc())) {
return NS_ERROR_UNEXPECTED;
}
@ -2726,14 +2730,26 @@ nsFrameLoader::MaybeCreateDocShell()
nsDocShell::Cast(mDocShell)->SetOriginAttributes(attrs);
// Typically there will be a window, however for some cases such as printing
// the document is cloned with a docshell that has no window. We check
// that the window exists to ensure we don't try to gather ancestors for
// those cases.
nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
if (!mDocShell->GetIsMozBrowser() &&
parentType == mDocShell->ItemType()) {
parentType == mDocShell->ItemType() &&
!doc->IsStaticDocument() && win) {
// Propagate through the ancestor principals.
nsTArray<nsCOMPtr<nsIPrincipal>> ancestorPrincipals;
// Make a copy, so we can modify it.
ancestorPrincipals = doc->AncestorPrincipals();
ancestorPrincipals.InsertElementAt(0, doc->NodePrincipal());
nsDocShell::Cast(mDocShell)->SetAncestorPrincipals(Move(ancestorPrincipals));
// Repeat for outer window IDs.
nsTArray<uint64_t> ancestorOuterWindowIDs;
ancestorOuterWindowIDs = doc->AncestorOuterWindowIDs();
ancestorOuterWindowIDs.InsertElementAt(0, win->WindowID());
nsDocShell::Cast(mDocShell)->SetAncestorOuterWindowIDs(Move(ancestorOuterWindowIDs));
}
ReallyLoadFrameScripts();

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

@ -465,6 +465,15 @@ public:
return mAncestorPrincipals;
}
/**
* Get the list of ancestor outerWindowIDs for a document that correspond to
* the ancestor principals (see above for more details).
*/
const nsTArray<uint64_t>& AncestorOuterWindowIDs() const
{
return mAncestorOuterWindowIDs;
}
/**
* Return the LoadGroup for the document. May return null.
*/
@ -3696,6 +3705,8 @@ protected:
// List of ancestor principals. This is set at the point a document
// is connected to a docshell and not mutated thereafter.
nsTArray<nsCOMPtr<nsIPrincipal>> mAncestorPrincipals;
// List of ancestor outerWindowIDs that correspond to the ancestor principals.
nsTArray<uint64_t> mAncestorOuterWindowIDs;
// Restyle root for servo's style system.
//

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

@ -73,7 +73,8 @@ public:
mSampleRate = mChannels = mFrames = 0;
}
/* Add a buffer to the mix. */
/* Add a buffer to the mix. The buffer can be null if there's nothing to mix
* but the callback is still needed. */
void Mix(AudioDataValue* aSamples,
uint32_t aChannels,
uint32_t aFrames,
@ -89,6 +90,10 @@ public:
MOZ_ASSERT(aChannels == mChannels);
MOZ_ASSERT(aSampleRate == mSampleRate);
if (!aSamples) {
return;
}
for (uint32_t i = 0; i < aFrames * aChannels; i++) {
mMixedAudio[i] += aSamples[i];
}

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

@ -319,7 +319,8 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
// Currently our decoder only knows how to output to ImageFormat::PLANAR_YCBCR
// format.
#if XP_WIN
if (aAllocator && aAllocator->GetCompositorBackendType()
if (!XRE_IsParentProcess() &&
aAllocator && aAllocator->GetCompositorBackendType()
== layers::LayersBackend::LAYERS_D3D11) {
RefPtr<layers::D3D11YCbCrImage> d3d11Image = new layers::D3D11YCbCrImage();
PlanarYCbCrData data = ConstructPlanarYCbCrData(aInfo, aBuffer, aPicture);

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

@ -410,7 +410,7 @@ public:
MOZ_ASSERT(mInactiveListeners.Length() == 0);
MOZ_ASSERT(mActiveListeners.Length() == 0);
RefPtr<MediaManager> mgr = MediaManager::GetIfExists();
MediaManager* mgr = MediaManager::GetIfExists();
if (!mgr) {
MOZ_ASSERT(false, "MediaManager should stay until everything is removed");
return;
@ -1289,7 +1289,10 @@ public:
self->mOnFailure.forget())));
NS_DispatchToMainThread(NS_NewRunnableFunction("MediaManager::SendPendingGUMRequest",
[]() -> void {
RefPtr<MediaManager> manager = MediaManager::GetInstance();
MediaManager* manager = MediaManager::GetIfExists();
if (!manager) {
return;
}
manager->SendPendingGUMRequest();
}));
return NS_OK;
@ -1356,7 +1359,6 @@ GetSources(MediaEngine *engine, MediaSourceEnum aSrcType,
// TODO: Remove once upgraded to GCC 4.8+ on linux. Bogus error on static func:
// error: 'this' was not captured for this lambda function
static auto& MediaManager_GetInstance = MediaManager::GetInstance;
static auto& MediaManager_ToJSArray = MediaManager::ToJSArray;
static auto& MediaManager_AnonymizeDevices = MediaManager::AnonymizeDevices;
@ -1419,7 +1421,10 @@ MediaManager::SelectSettings(
}
}
NS_DispatchToMainThread(NewRunnableFrom([id, badConstraint]() mutable {
RefPtr<MediaManager> mgr = MediaManager_GetInstance();
MediaManager* mgr = MediaManager::GetIfExists();
if (!mgr) {
return NS_OK;
}
RefPtr<PledgeChar> p = mgr->mOutstandingCharPledges.Remove(id);
if (p) {
p->Resolve(badConstraint);
@ -1548,7 +1553,10 @@ public:
}
NS_DispatchToMainThread(NS_NewRunnableFunction("MediaManager::SendPendingGUMRequest",
[]() -> void {
RefPtr<MediaManager> manager = MediaManager::GetInstance();
MediaManager* manager = MediaManager::GetIfExists();
if (!manager) {
return;
}
manager->SendPendingGUMRequest();
}));
return NS_OK;
@ -1726,7 +1734,8 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId,
fakeBackend = new MediaEngineDefault();
}
if ((!fakeCams && hasVideo) || (!fakeMics && hasAudio)) {
RefPtr<MediaManager> manager = MediaManager_GetInstance();
MediaManager* manager = MediaManager::GetIfExists();
MOZ_RELEASE_ASSERT(manager); // Must exist while media thread is alive
realBackend = manager->GetBackend(aWindowId);
// We need to listen to this event even JS didn't listen to it.
realBackend->AddDeviceChangeCallback(manager);
@ -1755,7 +1764,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId,
SourceSet* handoff = result.release();
NS_DispatchToMainThread(NewRunnableFrom([id, handoff]() mutable {
UniquePtr<SourceSet> result(handoff); // grab result
RefPtr<MediaManager> mgr = MediaManager_GetInstance();
MediaManager* mgr = MediaManager::GetIfExists();
if (!mgr) {
return NS_OK;
}
@ -2036,7 +2045,8 @@ int MediaManager::AddDeviceChangeCallback(DeviceChangeCallback* aCallback)
{
bool fakeDeviceChangeEventOn = mPrefs.mFakeDeviceChangeEventOn;
MediaManager::PostTask(NewTaskFrom([fakeDeviceChangeEventOn]() {
RefPtr<MediaManager> manager = MediaManager_GetInstance();
MediaManager* manager = MediaManager::GetIfExists();
MOZ_RELEASE_ASSERT(manager); // Must exist while media thread is alive
if (fakeDeviceChangeEventOn)
manager->GetBackend(0)->SetFakeDeviceChangeEvents();
}));
@ -2698,7 +2708,10 @@ MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
p->Then([id, aWindowId, aVideoType, aAudioType,
aFake](const nsCString& aOriginKey) mutable {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<MediaManager> mgr = MediaManager_GetInstance();
MediaManager* mgr = MediaManager::GetIfExists();
if (!mgr) {
return;
}
RefPtr<PledgeSourceSet> p = mgr->EnumerateRawDevices(aWindowId, aVideoType,
aAudioType, aFake);
@ -2711,7 +2724,7 @@ MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
UniquePtr<SourceSet> devices(aDevices); // secondary result
// Only run if window is still on our active list.
RefPtr<MediaManager> mgr = MediaManager_GetInstance();
MediaManager* mgr = MediaManager::GetIfExists();
if (!mgr) {
return NS_OK;
}
@ -3942,7 +3955,10 @@ SourceListener::ApplyConstraintsToTrack(
"MozNoiseSuppressionWarning",
aWindow);
RefPtr<MediaManager> mgr = MediaManager::GetInstance();
MediaManager* mgr = MediaManager::GetIfExists();
if (!mgr) {
return p.forget();
}
uint32_t id = mgr->mOutstandingVoidPledges.Append(*p);
uint64_t windowId = aWindow->WindowID();
bool isChrome = (aCallerType == dom::CallerType::System);
@ -3951,7 +3967,8 @@ SourceListener::ApplyConstraintsToTrack(
audioDevice, videoDevice,
c, isChrome]() mutable {
MOZ_ASSERT(MediaManager::IsInMediaThread());
RefPtr<MediaManager> mgr = MediaManager::GetInstance();
MediaManager* mgr = MediaManager::GetIfExists();
MOZ_RELEASE_ASSERT(mgr); // Must exist while media thread is alive
const char* badConstraint = nullptr;
nsresult rv = NS_OK;
@ -3975,7 +3992,7 @@ SourceListener::ApplyConstraintsToTrack(
NS_DispatchToMainThread(NewRunnableFrom([id, windowId, rv,
badConstraint]() mutable {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<MediaManager> mgr = MediaManager_GetInstance();
MediaManager* mgr = MediaManager::GetIfExists();
if (!mgr) {
return NS_OK;
}

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

@ -1115,23 +1115,17 @@ MediaStreamGraph::NotifyOutputData(AudioDataValue* aBuffer, size_t aFrames,
}
}
void
MediaStreamGraph::AssertOnGraphThreadOrNotRunning() const
bool
MediaStreamGraph::OnGraphThreadOrNotRunning() const
{
// either we're on the right thread (and calling CurrentDriver() is safe),
// or we're going to assert anyways, so don't cross-check CurrentDriver
#ifdef DEBUG
// or we're going to fail the assert anyway, so don't cross-check
// via CurrentDriver().
MediaStreamGraphImpl const * graph =
static_cast<MediaStreamGraphImpl const *>(this);
// if all the safety checks fail, assert we own the monitor
if (!graph->mDriver->OnThread()) {
if (!(graph->mDetectedNotRunning &&
graph->mLifecycleState > MediaStreamGraphImpl::LIFECYCLE_RUNNING &&
NS_IsMainThread())) {
graph->mMonitor.AssertCurrentThreadOwns();
}
}
#endif
return graph->mDetectedNotRunning ?
NS_IsMainThread() : graph->mDriver->OnThread();
}
bool
@ -1407,7 +1401,16 @@ MediaStreamGraphImpl::Process()
}
}
if (CurrentDriver()->AsAudioCallbackDriver() && ticksPlayed) {
if (CurrentDriver()->AsAudioCallbackDriver()) {
if (!ticksPlayed) {
// Nothing was played, so the mixer doesn't know how many frames were
// processed. We still tell it so AudioCallbackDriver knows how much has
// been processed. (bug 1406027)
mMixer.Mix(nullptr,
CurrentDriver()->AsAudioCallbackDriver()->OutputChannelCount(),
mStateComputedTime - mProcessedTime,
mSampleRate);
}
mMixer.FinishMixing();
}

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

@ -1367,7 +1367,10 @@ public:
void NotifyOutputData(AudioDataValue* aBuffer, size_t aFrames,
TrackRate aRate, uint32_t aChannels);
void AssertOnGraphThreadOrNotRunning() const;
void AssertOnGraphThreadOrNotRunning() const
{
MOZ_ASSERT(OnGraphThreadOrNotRunning());
}
protected:
explicit MediaStreamGraph(TrackRate aSampleRate)
@ -1380,6 +1383,10 @@ protected:
MOZ_COUNT_DTOR(MediaStreamGraph);
}
// Intended only for assertions, either on graph thread, not running, or
// with monitor held.
bool OnGraphThreadOrNotRunning() const;
// Media graph thread only
nsTArray<nsCOMPtr<nsIRunnable> > mPendingUpdateRunnables;

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

@ -456,7 +456,11 @@ public:
*/
GraphDriver* CurrentDriver() const
{
AssertOnGraphThreadOrNotRunning();
#ifdef DEBUG
if (!OnGraphThreadOrNotRunning()) {
mMonitor.AssertCurrentThreadOwns();
}
#endif
return mDriver;
}
@ -475,7 +479,10 @@ public:
*/
void SetCurrentDriver(GraphDriver* aDriver)
{
#ifdef DEBUG
mMonitor.AssertCurrentThreadOwns();
AssertOnGraphThreadOrNotRunning();
#endif
mDriver = aDriver;
}

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

@ -286,6 +286,18 @@ interface ChannelWrapper : EventTarget {
[Cached, Pure]
readonly attribute nsISupports? browserElement;
/**
* Returns an array of objects that combine the url and frameId from the
* ancestorPrincipals and ancestorOuterWindowIDs on loadInfo.
* The immediate parent is the first entry, the last entry is always the top
* level frame. It will be an empty list for toplevel window loads and
* non-subdocument resource loads within a toplevel window. For the latter,
* originURL will provide information on what window is doing the load. It
* will be null if the request is not associated with a window (e.g. XHR with
* mozBackgroundRequest = true).
*/
[Cached, Frozen, GetterThrows, Pure]
readonly attribute sequence<MozFrameAncestorInfo>? frameAncestors;
/**
* For HTTP requests, returns an array of request headers which will be, or

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

@ -73,7 +73,7 @@ namespace mozilla {
class Mutex;
namespace wr {
struct WrFontInstanceOptions;
struct FontInstanceOptions;
struct FontInstancePlatformOptions;
}
@ -836,7 +836,7 @@ public:
virtual bool GetFontInstanceData(FontInstanceDataOutput, void *) { return false; }
virtual bool GetWRFontInstanceOptions(Maybe<wr::WrFontInstanceOptions>* aOutOptions,
virtual bool GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
std::vector<FontVariation>* aOutVariations)
{

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

@ -8,6 +8,7 @@
#include "PathD2D.h"
#include "gfxFont.h"
#include "Logging.h"
#include "mozilla/webrender/WebRenderTypes.h"
using namespace std;
@ -300,6 +301,28 @@ ScaledFontDWrite::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
return true;
}
bool
ScaledFontDWrite::GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
std::vector<FontVariation>* aOutVariations)
{
AntialiasMode aaMode = GetDefaultAAMode();
if (aaMode != AntialiasMode::SUBPIXEL) {
wr::FontInstanceOptions options;
options.render_mode =
aaMode == AntialiasMode::NONE ? wr::FontRenderMode::Mono : wr::FontRenderMode::Alpha;
options.subpx_dir = wr::SubpixelDirection::Horizontal;
options.synthetic_italics = false;
*aOutOptions = Some(options);
}
wr::FontInstancePlatformOptions platformOptions;
platformOptions.use_embedded_bitmap = UseEmbeddedBitmaps();
platformOptions.force_gdi_rendering = ForceGDIMode();
*aOutPlatformOptions = Some(platformOptions);
return true;
}
already_AddRefed<ScaledFont>
UnscaledFontDWrite::CreateScaledFont(Float aGlyphSize,
const uint8_t* aInstanceData,

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

@ -56,6 +56,10 @@ public:
bool GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) override;
bool GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
std::vector<FontVariation>* aOutVariations) override;
AntialiasMode GetDefaultAAMode() override;
bool UseEmbeddedBitmaps() { return mUseEmbeddedBitmap; }

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

@ -6,6 +6,7 @@
#include "ScaledFontFontconfig.h"
#include "UnscaledFontFreeType.h"
#include "Logging.h"
#include "mozilla/webrender/WebRenderTypes.h"
#ifdef USE_SKIA
#include "skia/include/ports/SkTypeface_cairo.h"
@ -14,6 +15,17 @@
#include <fontconfig/fcfreetype.h>
namespace mozilla {
namespace wr {
enum {
FONT_FORCE_AUTOHINT = 1 << 0,
FONT_NO_AUTOHINT = 1 << 1,
FONT_EMBEDDED_BITMAP = 1 << 2,
FONT_EMBOLDEN = 1 << 3,
FONT_VERTICAL_LAYOUT = 1 << 4,
FONT_SUBPIXEL_BGR = 1 << 5
};
}
namespace gfx {
// On Linux and Android our "platform" font is a cairo_scaled_font_t and we use
@ -231,6 +243,124 @@ ScaledFontFontconfig::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBat
return true;
}
bool
ScaledFontFontconfig::GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
std::vector<FontVariation>* aOutVariations)
{
wr::FontInstanceOptions options;
options.render_mode = wr::FontRenderMode::Alpha;
options.subpx_dir = wr::SubpixelDirection::Horizontal;
options.synthetic_italics = false;
wr::FontInstancePlatformOptions platformOptions;
platformOptions.flags = 0;
platformOptions.lcd_filter = wr::FontLCDFilter::Legacy;
platformOptions.hinting = wr::FontHinting::Normal;
FcBool autohint;
if (FcPatternGetBool(mPattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch && autohint) {
platformOptions.flags |= wr::FONT_FORCE_AUTOHINT;
}
FcBool embolden;
if (FcPatternGetBool(mPattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch && embolden) {
platformOptions.flags |= wr::FONT_EMBOLDEN;
}
FcBool vertical;
if (FcPatternGetBool(mPattern, FC_VERTICAL_LAYOUT, 0, &vertical) == FcResultMatch && vertical) {
platformOptions.flags |= wr::FONT_VERTICAL_LAYOUT;
}
FcBool antialias;
if (FcPatternGetBool(mPattern, FC_ANTIALIAS, 0, &antialias) != FcResultMatch || antialias) {
int rgba;
if (FcPatternGetInteger(mPattern, FC_RGBA, 0, &rgba) == FcResultMatch) {
switch (rgba) {
case FC_RGBA_RGB:
case FC_RGBA_BGR:
case FC_RGBA_VRGB:
case FC_RGBA_VBGR:
options.render_mode = wr::FontRenderMode::Subpixel;
if (rgba == FC_RGBA_VRGB || rgba == FC_RGBA_VBGR) {
options.subpx_dir = wr::SubpixelDirection::Vertical;
}
platformOptions.hinting = wr::FontHinting::LCD;
if (rgba == FC_RGBA_BGR || rgba == FC_RGBA_VBGR) {
platformOptions.flags |= wr::FONT_SUBPIXEL_BGR;
}
break;
case FC_RGBA_NONE:
case FC_RGBA_UNKNOWN:
default:
break;
}
}
if (options.render_mode == wr::FontRenderMode::Subpixel) {
int filter;
if (FcPatternGetInteger(mPattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) {
switch (filter) {
case FC_LCD_NONE:
platformOptions.lcd_filter = wr::FontLCDFilter::None;
break;
case FC_LCD_DEFAULT:
platformOptions.lcd_filter = wr::FontLCDFilter::Default;
break;
case FC_LCD_LIGHT:
platformOptions.lcd_filter = wr::FontLCDFilter::Light;
break;
case FC_LCD_LEGACY:
default:
break;
}
}
}
// Match cairo-ft's handling of embeddedbitmap:
// If AA is explicitly disabled, leave bitmaps enabled.
// Otherwise, disable embedded bitmaps unless explicitly enabled.
FcBool bitmap;
if (FcPatternGetBool(mPattern, FC_EMBEDDED_BITMAP, 0, &bitmap) == FcResultMatch && bitmap) {
platformOptions.flags |= wr::FONT_EMBEDDED_BITMAP;
}
} else {
options.render_mode = wr::FontRenderMode::Mono;
options.subpx_dir = wr::SubpixelDirection::None;
platformOptions.hinting = wr::FontHinting::Mono;
platformOptions.flags |= wr::FONT_EMBEDDED_BITMAP;
}
FcBool hinting;
int hintstyle;
if (FcPatternGetBool(mPattern, FC_HINTING, 0, &hinting) != FcResultMatch || hinting) {
if (FcPatternGetInteger(mPattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) {
hintstyle = FC_HINT_FULL;
}
} else {
hintstyle = FC_HINT_NONE;
}
if (hintstyle == FC_HINT_NONE) {
platformOptions.hinting = wr::FontHinting::None;
} else if (options.render_mode != wr::FontRenderMode::Mono) {
switch (hintstyle) {
case FC_HINT_SLIGHT:
platformOptions.hinting = wr::FontHinting::Light;
break;
case FC_HINT_MEDIUM:
platformOptions.hinting = wr::FontHinting::Normal;
break;
case FC_HINT_FULL:
default:
break;
}
}
*aOutOptions = Some(options);
*aOutPlatformOptions = Some(platformOptions);
return true;
}
already_AddRefed<ScaledFont>
UnscaledFontFontconfig::CreateScaledFont(Float aGlyphSize,
const uint8_t* aInstanceData,

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

@ -34,6 +34,10 @@ public:
bool GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) override;
bool GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
std::vector<FontVariation>* aOutVariations) override;
private:
friend class NativeFontResourceFontconfig;
friend class UnscaledFontFontconfig;

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

@ -359,7 +359,7 @@ ScaledFontMac::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton)
}
bool
ScaledFontMac::GetWRFontInstanceOptions(Maybe<wr::WrFontInstanceOptions>* aOutOptions,
ScaledFontMac::GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
std::vector<FontVariation>* aOutVariations)
{

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

@ -52,7 +52,7 @@ public:
bool GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) override;
bool GetWRFontInstanceOptions(Maybe<wr::WrFontInstanceOptions>* aOutOptions,
bool GetWRFontInstanceOptions(Maybe<wr::FontInstanceOptions>* aOutOptions,
Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
std::vector<FontVariation>* aOutVariations) override;

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

@ -79,4 +79,4 @@ to make sure that mozjs_sys also has its Cargo.lock file updated if needed, henc
the need to run the cargo update command in js/src as well. Hopefully this will
be resolved soon.
Latest Commit: a884e676449e5b41669cd6de51af14e70cbe3512
Latest Commit: 6440dff485271cdfd24a22c920cea31e01e2b164

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

@ -289,9 +289,24 @@ D3D11YCbCrRecycleAllocator::Allocate(SurfaceFormat aFormat,
1, 1);
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
RefPtr<ID3D10Multithread> mt;
HRESULT hr = mDevice->QueryInterface(
(ID3D10Multithread**)getter_AddRefs(mt));
if (FAILED(hr) || !mt) {
gfxCriticalError() << "Multithread safety interface not supported. " << hr;
return nullptr;
}
if (!mt->GetMultithreadProtected()) {
gfxCriticalError() << "Device used not marked as multithread-safe.";
return nullptr;
}
D3D11MTAutoEnter mtAutoEnter(mt.forget());
RefPtr<ID3D11Texture2D> textureY;
HRESULT hr =
mDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureY));
hr = mDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureY));
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
newDesc.Width = CbCrSize.width;

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

@ -1,6 +1,6 @@
[package]
name = "webrender"
version = "0.52.0"
version = "0.52.1"
authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
license = "MPL-2.0"
repository = "https://github.com/servo/webrender"

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

@ -1,158 +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/. */
extern crate gleam;
extern crate glutin;
extern crate webrender;
#[path = "common/boilerplate.rs"]
mod boilerplate;
use boilerplate::{Example, HandyDandyRectBuilder};
use webrender::api::*;
struct App {
cursor_position: WorldPoint,
}
impl Example for App {
fn render(
&mut self,
_api: &RenderApi,
builder: &mut DisplayListBuilder,
_resources: &mut ResourceUpdates,
layout_size: LayoutSize,
pipeline_id: PipelineId,
_document_id: DocumentId,
) {
let bounds = LayoutRect::new(LayoutPoint::zero(), layout_size);
let info = LayoutPrimitiveInfo::new(bounds);
builder.push_stacking_context(
&info,
ScrollPolicy::Scrollable,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
);
let outer_scroll_frame_rect = (100, 100).to(600, 400);
let info = LayoutPrimitiveInfo::new(outer_scroll_frame_rect);
builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 1.0));
let nested_clip_id = builder.define_scroll_frame(
None,
(100, 100).to(1000, 1000),
outer_scroll_frame_rect,
vec![],
None,
ScrollSensitivity::ScriptAndInputEvents,
);
builder.push_clip_id(nested_clip_id);
let mut builder2 = DisplayListBuilder::new(pipeline_id, layout_size);
let mut builder3 = DisplayListBuilder::new(pipeline_id, layout_size);
let info = LayoutPrimitiveInfo::new((110, 110).to(210, 210));
builder3.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
// A fixed position rectangle should be fixed to the reference frame that starts
// in the outer display list.
let info = LayoutPrimitiveInfo::new((220, 110).to(320, 210));
builder3.push_stacking_context(
&info,
ScrollPolicy::Fixed,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
);
let info = LayoutPrimitiveInfo::new((0, 0).to(100, 100));
builder3.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
builder3.pop_stacking_context();
// Now we push an inner scroll frame that should have the same id as the outer one,
// but the WebRender nested display list replacement code should convert it into
// a unique ClipId.
let inner_scroll_frame_rect = (330, 110).to(530, 360);
let info = LayoutPrimitiveInfo::new(inner_scroll_frame_rect);
builder3.push_rect(&info, ColorF::new(1.0, 0.0, 1.0, 0.5));
let inner_nested_clip_id = builder3.define_scroll_frame(
None,
(330, 110).to(2000, 2000),
inner_scroll_frame_rect,
vec![],
None,
ScrollSensitivity::ScriptAndInputEvents,
);
builder3.push_clip_id(inner_nested_clip_id);
let info = LayoutPrimitiveInfo::new((340, 120).to(440, 220));
builder3.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
builder3.pop_clip_id();
let (_, _, built_list) = builder3.finalize();
builder2.push_nested_display_list(&built_list);
let (_, _, built_list) = builder2.finalize();
builder.push_nested_display_list(&built_list);
builder.pop_clip_id();
builder.pop_stacking_context();
}
fn on_event(&mut self, event: glutin::Event, api: &RenderApi, document_id: DocumentId) -> bool {
match event {
glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(key)) => {
let offset = match key {
glutin::VirtualKeyCode::Down => (0.0, -10.0),
glutin::VirtualKeyCode::Up => (0.0, 10.0),
glutin::VirtualKeyCode::Right => (-10.0, 0.0),
glutin::VirtualKeyCode::Left => (10.0, 0.0),
_ => return false,
};
api.scroll(
document_id,
ScrollLocation::Delta(LayoutVector2D::new(offset.0, offset.1)),
self.cursor_position,
ScrollEventPhase::Start,
);
}
glutin::Event::MouseMoved(x, y) => {
self.cursor_position = WorldPoint::new(x as f32, y as f32);
}
glutin::Event::MouseWheel(delta, _, event_cursor_position) => {
if let Some((x, y)) = event_cursor_position {
self.cursor_position = WorldPoint::new(x as f32, y as f32);
}
const LINE_HEIGHT: f32 = 38.0;
let (dx, dy) = match delta {
glutin::MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
glutin::MouseScrollDelta::PixelDelta(dx, dy) => (dx, dy),
};
api.scroll(
document_id,
ScrollLocation::Delta(LayoutVector2D::new(dx, dy)),
self.cursor_position,
ScrollEventPhase::Start,
);
}
_ => (),
}
false
}
}
fn main() {
let mut app = App {
cursor_position: WorldPoint::zero(),
};
boilerplate::main_wrapper(&mut app, None);
}

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

@ -27,8 +27,7 @@ struct ClipCorner {
vec4 outer_inner_radius;
};
ClipCorner fetch_clip_corner(ivec2 address, int index) {
address += ivec2(2 + 2 * index, 0);
ClipCorner fetch_clip_corner(ivec2 address) {
vec4 data[2] = fetch_from_resource_cache_2_direct(address);
return ClipCorner(RectWithSize(data[0].xy, data[0].zw), data[1]);
}
@ -45,10 +44,22 @@ ClipData fetch_clip(ivec2 address) {
ClipData clip;
clip.rect = fetch_clip_rect(address);
clip.top_left = fetch_clip_corner(address, 0);
clip.top_right = fetch_clip_corner(address, 1);
clip.bottom_left = fetch_clip_corner(address, 2);
clip.bottom_right = fetch_clip_corner(address, 3);
// Read the corners in groups of two texels, and adjust the read address
// before every read.
// The address adjustment is done inside this function, and not by passing
// the corner index to fetch_clip_corner and computing the correct address
// there, because doing so was hitting a driver bug on certain Intel macOS
// drivers which creates wrong results when doing arithmetic with integer
// variables (under certain, unknown, circumstances).
address.x += 2;
clip.top_left = fetch_clip_corner(address);
address.x += 2;
clip.top_right = fetch_clip_corner(address);
address.x += 2;
clip.bottom_left = fetch_clip_corner(address);
address.x += 2;
clip.bottom_right = fetch_clip_corner(address);
return clip;
}

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

@ -38,7 +38,7 @@ void main(void) {
// Glyphs size is already in device-pixels.
// The render task origin is in device-pixels. Offset that by
// the glyph offset, relative to its primitive bounding rect.
vec2 size = res.uv_rect.zw - res.uv_rect.xy;
vec2 size = (res.uv_rect.zw - res.uv_rect.xy) * res.scale;
vec2 local_pos = glyph.offset + vec2(res.offset.x, -res.offset.y) / uDevicePixelRatio;
vec2 origin = prim.task.render_target_origin +
uDevicePixelRatio * (local_pos + shadow.offset - shadow_geom.local_rect.p0);

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

@ -627,11 +627,12 @@ struct GlyphResource {
vec4 uv_rect;
float layer;
vec2 offset;
float scale;
};
GlyphResource fetch_glyph_resource(int address) {
vec4 data[2] = fetch_from_resource_cache_2(address);
return GlyphResource(data[0], data[1].x, data[1].yz);
return GlyphResource(data[0], data[1].x, data[1].yz, data[1].w);
}
struct ImageResource {

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

@ -110,10 +110,10 @@ void write_color(vec4 color0, vec4 color1, int style, vec2 delta, int instance_k
break;
}
vColor00 = vec4(color0.rgb * modulate.x, color0.a);
vColor01 = vec4(color0.rgb * modulate.y, color0.a);
vColor10 = vec4(color1.rgb * modulate.z, color1.a);
vColor11 = vec4(color1.rgb * modulate.w, color1.a);
vColor00 = vec4(clamp(color0.rgb * modulate.x, vec3(0.0), vec3(1.0)), color0.a);
vColor01 = vec4(clamp(color0.rgb * modulate.y, vec3(0.0), vec3(1.0)), color0.a);
vColor10 = vec4(clamp(color1.rgb * modulate.z, vec3(0.0), vec3(1.0)), color1.a);
vColor11 = vec4(clamp(color1.rgb * modulate.w, vec3(0.0), vec3(1.0)), color1.a);
}
int select_style(int color_select, vec2 fstyle) {
@ -325,8 +325,11 @@ void main(void) {
alpha = min(alpha, do_clip());
// Find the appropriate distance to apply the AA smoothstep over.
// Using 0.7 instead of 0.5 for the step compensates for the fact that smoothstep
// is smooth at its endpoints and has a steeper maximum slope than a linear ramp.
vec2 fw = fwidth(local_pos);
float afwidth = length(fw);
float aa_step = 0.7 * length(fw);
float distance_for_color;
float color_mix_factor;
@ -336,28 +339,39 @@ void main(void) {
if (all(lessThan(local_pos * vClipSign, vClipCenter * vClipSign))) {
vec2 p = local_pos - vClipCenter;
// The coordinate system is snapped to pixel boundaries. To sample the distance,
// however, we are interested in the center of the pixels which introduces an
// error of half a pixel towards the exterior of the curve (See issue #1750).
// This error is corrected by offsetting the distance by half a device pixel.
// This not entirely correct: it leaves an error that varries between
// 0 and (sqrt(2) - 1)/2 = 0.2 pixels but it is hardly noticeable and is better
// than the constant sqrt(2)/2 px error without the correction.
// To correct this exactly we would need to offset p by half a pixel in the
// direction of the center of the ellipse (a different offset for each corner).
// A half device pixel in css pixels (using the average of width and height in case
// there is any kind of transform applied).
float half_px = 0.25 * (fw.x + fw.y);
// Get signed distance from the inner/outer clips.
float d0 = distance_to_ellipse(p, vRadii0.xy);
float d1 = distance_to_ellipse(p, vRadii0.zw);
float d2 = distance_to_ellipse(p, vRadii1.xy);
float d3 = distance_to_ellipse(p, vRadii1.zw);
float d0 = distance_to_ellipse(p, vRadii0.xy) + half_px;
float d1 = distance_to_ellipse(p, vRadii0.zw) + half_px;
float d2 = distance_to_ellipse(p, vRadii1.xy) + half_px;
float d3 = distance_to_ellipse(p, vRadii1.zw) + half_px;
// SDF subtract main radii
float d_main = max(d0, 0.5 * afwidth - d1);
float d_main = max(d0, aa_step - d1);
// SDF subtract inner radii (double style borders)
float d_inner = max(d2 - 0.5 * afwidth, -d3);
float d_inner = max(d2 - aa_step, -d3);
// Select how to combine the SDF based on border style.
float d = mix(max(d_main, -d_inner), d_main, vSDFSelect);
// Only apply AA to fragments outside the signed distance field.
alpha = min(alpha, 1.0 - smoothstep(0.0, 0.5 * afwidth, d));
alpha = min(alpha, 1.0 - smoothstep(0.0, aa_step, d));
// Get the groove/ridge mix factor.
color_mix_factor = smoothstep(-0.5 * afwidth,
0.5 * afwidth,
-d2);
color_mix_factor = smoothstep(-aa_step, aa_step, -d2);
} else {
// Handle the case where the fragment is outside the clip
// region in a corner. This occurs when border width is
@ -389,7 +403,7 @@ void main(void) {
// Select color based on side of line. Get distance from the
// reference line, and then apply AA along the edge.
float ld = distance_to_line(vColorEdgeLine.xy, vColorEdgeLine.zw, local_pos);
float m = smoothstep(-0.5 * afwidth, 0.5 * afwidth, ld);
float m = smoothstep(-aa_step, aa_step, ld);
vec4 color = mix(color0, color1, m);
oFragColor = color * vec4(1.0, 1.0, 1.0, alpha);

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

@ -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/. */
void main(void) {
vec2 uv = clamp(vUv.xy, vUvBounds.xy, vUvBounds.zw);
oFragColor = texture(sCacheRGBA8, vec3(uv, vUv.z));
}

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

@ -6,3 +6,34 @@
varying vec3 vUv;
flat varying vec4 vUvBounds;
#ifdef WR_VERTEX_SHADER
void main(void) {
CompositeInstance ci = fetch_composite_instance();
AlphaBatchTask dest_task = fetch_alpha_batch_task(ci.render_task_index);
AlphaBatchTask src_task = fetch_alpha_batch_task(ci.src_task_index);
vec2 dest_origin = dest_task.render_target_origin -
dest_task.screen_space_origin +
vec2(ci.user_data0, ci.user_data1);
vec2 local_pos = mix(dest_origin,
dest_origin + src_task.size,
aPosition.xy);
vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
vec2 st0 = src_task.render_target_origin;
vec2 st1 = src_task.render_target_origin + src_task.size;
vUv = vec3(mix(st0, st1, aPosition.xy) / texture_size, src_task.render_target_layer_index);
vUvBounds = vec4(st0 + 0.5, st1 - 0.5) / texture_size.xyxy;
gl_Position = uTransform * vec4(local_pos, ci.z, 1.0);
}
#endif
#ifdef WR_FRAGMENT_SHADER
void main(void) {
vec2 uv = clamp(vUv.xy, vUvBounds.xy, vUvBounds.zw);
oFragColor = texture(sCacheRGBA8, vec3(uv, vUv.z));
}
#endif

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

@ -1,25 +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/. */
void main(void) {
CompositeInstance ci = fetch_composite_instance();
AlphaBatchTask dest_task = fetch_alpha_batch_task(ci.render_task_index);
AlphaBatchTask src_task = fetch_alpha_batch_task(ci.src_task_index);
vec2 dest_origin = dest_task.render_target_origin -
dest_task.screen_space_origin +
vec2(ci.user_data0, ci.user_data1);
vec2 local_pos = mix(dest_origin,
dest_origin + src_task.size,
aPosition.xy);
vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
vec2 st0 = src_task.render_target_origin;
vec2 st1 = src_task.render_target_origin + src_task.size;
vUv = vec3(mix(st0, st1, aPosition.xy) / texture_size, src_task.render_target_layer_index);
vUvBounds = vec4(st0 + 0.5, st1 - 0.5) / texture_size.xyxy;
gl_Position = uTransform * vec4(local_pos, ci.z, 1.0);
}

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

@ -53,6 +53,8 @@ void main(void) {
// Whether to repeat the gradient instead of clamping.
vGradientRepeat = float(int(gradient.start_end_radius_ratio_xy_extend_mode.w) != EXTEND_MODE_CLAMP);
write_clip(vi.screen_pos, prim.clip_area);
}
#endif
@ -104,8 +106,21 @@ void main(void) {
}
}
oFragColor = sample_gradient(vGradientAddress,
vec4 color = sample_gradient(vGradientAddress,
offset,
vGradientRepeat);
// Un-premultiply the color from sampling the gradient.
if (color.a > 0.0) {
color.rgb /= color.a;
// Apply the clip mask
color.a = min(color.a, do_clip());
// Pre-multiply the result.
color.rgb *= color.a;
}
oFragColor = color;
}
#endif

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

@ -30,7 +30,7 @@ void main(void) {
vec2(res.offset.x, -res.offset.y) / uDevicePixelRatio;
RectWithSize local_rect = RectWithSize(local_pos,
(res.uv_rect.zw - res.uv_rect.xy) / uDevicePixelRatio);
(res.uv_rect.zw - res.uv_rect.xy) * res.scale / uDevicePixelRatio);
#ifdef WR_FEATURE_TRANSFORM
TransformVertexInfo vi = write_transform_vertex(local_rect,
@ -57,7 +57,7 @@ void main(void) {
vec2 st0 = res.uv_rect.xy / texture_size;
vec2 st1 = res.uv_rect.zw / texture_size;
vColor = text.color;
vColor = vec4(text.color.rgb * text.color.a, text.color.a);
vUv = vec3(mix(st0, st1, f), res.layer);
vUvBorder = (res.uv_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy;
}
@ -71,13 +71,14 @@ void main(void) {
oFragColor = texture(sColor0, tc);
#else
vec4 color = texture(sColor0, tc) * vColor;
float alpha = 1.0;
#ifdef WR_FEATURE_TRANSFORM
float a = 0.0;
init_transform_fs(vLocalPos, a);
color.a *= a;
alpha *= a;
#endif
color.a = min(color.a, do_clip());
oFragColor = color;
alpha = min(alpha, do_clip());
oFragColor = color * alpha;
#endif
}
#endif

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

@ -183,6 +183,11 @@ pub fn build_shader_strings(
vs_source.push_str(gl_version_string);
fs_source.push_str(gl_version_string);
// Insert the shader name to make debugging easier.
let name_string = format!("// {}\n", base_filename);
vs_source.push_str(&name_string);
fs_source.push_str(&name_string);
// Define a constant depending on whether we are compiling VS or FS.
vs_source.push_str(SHADER_KIND_VERTEX);
fs_source.push_str(SHADER_KIND_FRAGMENT);

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

@ -31,80 +31,12 @@ static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF {
a: 0.6,
};
/// Nested display lists cause two types of replacements to ClipIds inside the nesting:
/// 1. References to the root scroll frame are replaced by the ClipIds that
/// contained the nested display list.
/// 2. Other ClipIds (that aren't custom or reference frames) are assumed to be
/// local to the nested display list and are converted to an id that is unique
/// outside of the nested display list as well.
///
/// This structure keeps track of what ids are the "root" for one particular level of
/// nesting as well as keeping and index, which can make ClipIds used internally unique
/// in the full ClipScrollTree.
#[derive(Debug)]
struct NestedDisplayListInfo {
/// The index of this nested display list, which is used to generate
/// new ClipIds for clips that are defined inside it.
nest_index: u64,
/// The ClipId of the scroll frame node which contains this nested
/// display list. This is used to replace references to the root with
/// the proper ClipId.
scroll_node_id: ClipId,
/// The ClipId of the clip node which contains this nested display list.
/// This is used to replace references to the root with the proper ClipId.
clip_node_id: ClipId,
}
impl NestedDisplayListInfo {
fn convert_id_to_nested(&self, id: &ClipId) -> ClipId {
match *id {
ClipId::Clip(id, _, pipeline_id) => ClipId::Clip(id, self.nest_index, pipeline_id),
_ => *id,
}
}
fn convert_scroll_id_to_nested(&self, id: &ClipId) -> ClipId {
if id.pipeline_id() != self.scroll_node_id.pipeline_id() {
return *id;
}
if id.is_root_scroll_node() {
self.scroll_node_id
} else {
self.convert_id_to_nested(id)
}
}
fn convert_clip_id_to_nested(&self, id: &ClipId) -> ClipId {
if id.pipeline_id() != self.clip_node_id.pipeline_id() {
return *id;
}
if id.is_root_scroll_node() {
self.clip_node_id
} else {
self.convert_id_to_nested(id)
}
}
fn convert_new_id_to_nested(&self, id: &ClipId) -> ClipId {
if id.pipeline_id() != self.clip_node_id.pipeline_id() {
return *id;
}
self.convert_id_to_nested(id)
}
}
struct FlattenContext<'a> {
scene: &'a Scene,
builder: &'a mut FrameBuilder,
resource_cache: &'a ResourceCache,
tiled_image_map: TiledImageMap,
replacements: Vec<(ClipId, ClipId)>,
nested_display_list_info: Vec<NestedDisplayListInfo>,
current_nested_display_list_index: u64,
}
impl<'a> FlattenContext<'a> {
@ -119,49 +51,9 @@ impl<'a> FlattenContext<'a> {
resource_cache,
tiled_image_map: resource_cache.get_tiled_image_map(),
replacements: Vec::new(),
nested_display_list_info: Vec::new(),
current_nested_display_list_index: 0,
}
}
fn push_nested_display_list_ids(&mut self, info: ClipAndScrollInfo) {
self.current_nested_display_list_index += 1;
self.nested_display_list_info.push(NestedDisplayListInfo {
nest_index: self.current_nested_display_list_index,
scroll_node_id: info.scroll_node_id,
clip_node_id: info.clip_node_id(),
});
}
fn pop_nested_display_list_ids(&mut self) {
self.nested_display_list_info.pop();
}
fn convert_new_id_to_nested(&self, id: &ClipId) -> ClipId {
if let Some(nested_info) = self.nested_display_list_info.last() {
nested_info.convert_new_id_to_nested(id)
} else {
*id
}
}
fn convert_clip_scroll_info_to_nested(&self, info: &mut ClipAndScrollInfo) {
if let Some(nested_info) = self.nested_display_list_info.last() {
info.scroll_node_id = nested_info.convert_scroll_id_to_nested(&info.scroll_node_id);
info.clip_node_id = info.clip_node_id
.map(|ref id| nested_info.convert_clip_id_to_nested(id));
}
// We only want to produce nested ClipIds if we are in a nested display
// list situation.
debug_assert!(
!info.scroll_node_id.is_nested() || !self.nested_display_list_info.is_empty()
);
debug_assert!(
!info.clip_node_id().is_nested() || !self.nested_display_list_info.is_empty()
);
}
/// Since WebRender still handles fixed position and reference frame content internally
/// we need to apply this table of id replacements only to the id that affects the
/// position of a node. We can eventually remove this when clients start handling
@ -337,9 +229,8 @@ impl Frame {
new_clip_id: &ClipId,
clip_region: ClipRegion,
) {
let new_clip_id = context.convert_new_id_to_nested(new_clip_id);
context.builder.add_clip_node(
new_clip_id,
*new_clip_id,
*parent_id,
pipeline_id,
clip_region,
@ -367,9 +258,8 @@ impl Frame {
&mut self.clip_scroll_tree,
);
let new_scroll_frame_id = context.convert_new_id_to_nested(new_scroll_frame_id);
context.builder.add_scroll_frame(
new_scroll_frame_id,
*new_scroll_frame_id,
clip_id,
pipeline_id,
&frame_rect,
@ -555,7 +445,6 @@ impl Frame {
reference_frame_relative_offset: LayerVector2D,
) -> Option<BuiltDisplayListIter<'a>> {
let mut clip_and_scroll = item.clip_and_scroll();
context.convert_clip_scroll_info_to_nested(&mut clip_and_scroll);
let unreplaced_scroll_id = clip_and_scroll.scroll_node_id;
clip_and_scroll.scroll_node_id =
@ -777,22 +666,13 @@ impl Frame {
}
SpecificDisplayItem::StickyFrame(ref info) => {
let frame_rect = item.rect().translate(&reference_frame_relative_offset);
let new_clip_id = context.convert_new_id_to_nested(&info.id);
self.clip_scroll_tree.add_sticky_frame(
new_clip_id,
info.id,
clip_and_scroll.scroll_node_id, /* parent id */
frame_rect,
info.sticky_frame_info,
);
}
SpecificDisplayItem::PushNestedDisplayList => {
// Using the clip and scroll already processed for nesting here
// means that in the case of multiple nested display lists, we
// will enter the outermost ids into the table and avoid having
// to do a replacement for every level of nesting.
context.push_nested_display_list_ids(clip_and_scroll);
}
SpecificDisplayItem::PopNestedDisplayList => context.pop_nested_display_list_ids(),
// Do nothing; these are dummy items for the display list parser
SpecificDisplayItem::SetGradientStops => {}

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

@ -10,7 +10,7 @@ use api::{GlyphInstance, GlyphOptions, GradientStop, HitTestFlags, HitTestItem,
use api::{ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect};
use api::{LayerSize, LayerToScrollTransform, LayerVector2D, LayoutVector2D, LineOrientation};
use api::{LineStyle, LocalClip, POINT_RELATIVE_TO_PIPELINE_VIEWPORT, PipelineId, RepeatMode};
use api::{ScrollSensitivity, SubpixelDirection, Shadow, TileOffset, TransformStyle};
use api::{ScrollSensitivity, Shadow, TileOffset, TransformStyle};
use api::{WorldPixel, WorldPoint, YuvColorSpace, YuvData, device_length};
use app_units::Au;
use border::ImageBorderSegment;
@ -21,12 +21,13 @@ use euclid::{SideOffsets2D, vec2, vec3};
use frame::FrameId;
use gpu_cache::GpuCache;
use internal_types::{FastHashMap, FastHashSet, HardwareCompositeOp};
use picture::PicturePrimitive;
use plane_split::{BspSplitter, Polygon, Splitter};
use prim_store::{BoxShadowPrimitiveCpu, TexelRect, YuvImagePrimitiveCpu};
use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, LinePrimitive, PrimitiveKind};
use prim_store::{PrimitiveContainer, PrimitiveIndex};
use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu};
use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu, ShadowPrimitiveCpu};
use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu};
use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
use render_task::{AlphaRenderItem, ClipWorkItem, RenderTask};
use render_task::{RenderTaskId, RenderTaskLocation, RenderTaskTree};
@ -584,11 +585,7 @@ impl FrameBuilder {
clip_and_scroll: ClipAndScrollInfo,
info: &LayerPrimitiveInfo,
) {
let prim = ShadowPrimitiveCpu {
shadow,
primitives: Vec::new(),
render_task_id: None,
};
let prim = PicturePrimitive::new_shadow(shadow);
// Create an empty shadow primitive. Insert it into
// the draw lists immediately so that it will be drawn
@ -598,7 +595,7 @@ impl FrameBuilder {
clip_and_scroll,
info,
Vec::new(),
PrimitiveContainer::Shadow(prim),
PrimitiveContainer::Picture(prim),
);
self.shadow_prim_stack.push(prim_index);
@ -614,9 +611,10 @@ impl FrameBuilder {
// safe to offset the local rect by the offset of the shadow, which
// is then used when blitting the shadow to the final location.
let metadata = &mut self.prim_store.cpu_metadata[prim_index.0];
let prim = &self.prim_store.cpu_shadows[metadata.cpu_prim_index.0];
let prim = &self.prim_store.cpu_pictures[metadata.cpu_prim_index.0];
let shadow = prim.as_shadow();
metadata.local_rect = metadata.local_rect.translate(&prim.shadow.offset);
metadata.local_rect = metadata.local_rect.translate(&shadow.offset);
}
pub fn add_solid_rectangle(
@ -686,9 +684,10 @@ impl FrameBuilder {
let mut fast_shadow_prims = Vec::new();
for shadow_prim_index in &self.shadow_prim_stack {
let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0];
let shadow_prim = &self.prim_store.cpu_shadows[shadow_metadata.cpu_prim_index.0];
if shadow_prim.shadow.blur_radius == 0.0 {
fast_shadow_prims.push(shadow_prim.shadow);
let picture = &self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0];
let shadow = picture.as_shadow();
if shadow.blur_radius == 0.0 {
fast_shadow_prims.push(shadow.clone());
}
}
for shadow in fast_shadow_prims {
@ -720,18 +719,19 @@ impl FrameBuilder {
for shadow_prim_index in &self.shadow_prim_stack {
let shadow_metadata = &mut self.prim_store.cpu_metadata[shadow_prim_index.0];
debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Shadow);
let shadow_prim =
&mut self.prim_store.cpu_shadows[shadow_metadata.cpu_prim_index.0];
debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Picture);
let picture =
&mut self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0];
let blur_radius = picture.as_shadow().blur_radius;
// Only run real blurs here (fast path zero blurs are handled above).
if shadow_prim.shadow.blur_radius > 0.0 {
if blur_radius > 0.0 {
let shadow_rect = new_rect.inflate(
shadow_prim.shadow.blur_radius,
shadow_prim.shadow.blur_radius,
blur_radius,
blur_radius,
);
shadow_metadata.local_rect = shadow_metadata.local_rect.union(&shadow_rect);
shadow_prim.primitives.push(prim_index);
picture.add_primitive(prim_index, clip_and_scroll);
}
}
}
@ -1132,19 +1132,18 @@ impl FrameBuilder {
// TODO(gw): Use a proper algorithm to select
// whether this item should be rendered with
// subpixel AA!
let mut default_render_mode = self.config
let mut render_mode = self.config
.default_font_render_mode
.limit_by(font.render_mode);
if let Some(options) = glyph_options {
default_render_mode = default_render_mode.limit_by(options.render_mode);
render_mode = render_mode.limit_by(options.render_mode);
}
// There are some conditions under which we can't use
// subpixel text rendering, even if enabled.
let mut normal_render_mode = default_render_mode;
if normal_render_mode == FontRenderMode::Subpixel {
if render_mode == FontRenderMode::Subpixel {
if color.a != 1.0 {
normal_render_mode = FontRenderMode::Alpha;
render_mode = FontRenderMode::Alpha;
}
// text on a stacking context that has filters
@ -1155,36 +1154,17 @@ impl FrameBuilder {
if let Some(sc_index) = self.stacking_context_stack.last() {
let stacking_context = &self.stacking_context_store[sc_index.0];
if stacking_context.composite_ops.count() > 0 {
normal_render_mode = FontRenderMode::Alpha;
render_mode = FontRenderMode::Alpha;
}
}
}
let color = match font.render_mode {
FontRenderMode::Bitmap => ColorF::new(1.0, 1.0, 1.0, 1.0),
FontRenderMode::Subpixel |
FontRenderMode::Alpha |
FontRenderMode::Mono => *color,
};
// Shadows never use subpixel AA, but need to respect the alpha/mono flag
// for reftests.
let (shadow_render_mode, subpx_dir) = match default_render_mode {
FontRenderMode::Subpixel | FontRenderMode::Alpha => {
// TODO(gw): Expose subpixel direction in API once WR supports
// vertical text runs.
(FontRenderMode::Alpha, font.subpx_dir)
}
FontRenderMode::Mono => (FontRenderMode::Mono, SubpixelDirection::None),
FontRenderMode::Bitmap => (FontRenderMode::Bitmap, font.subpx_dir),
};
let prim_font = FontInstance::new(
font.font_key,
font.size,
color,
normal_render_mode,
subpx_dir,
*color,
render_mode,
font.subpx_dir,
font.platform_options,
font.variations.clone(),
font.synthetic_italics,
@ -1195,9 +1175,7 @@ impl FrameBuilder {
glyph_count,
glyph_gpu_blocks: Vec::new(),
glyph_keys: Vec::new(),
shadow_render_mode,
offset: run_offset,
color: color,
};
// Text shadows that have a blur radius of 0 need to be rendered as normal
@ -1211,20 +1189,18 @@ impl FrameBuilder {
let mut fast_shadow_prims = Vec::new();
for shadow_prim_index in &self.shadow_prim_stack {
let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0];
let shadow_prim = &self.prim_store.cpu_shadows[shadow_metadata.cpu_prim_index.0];
if shadow_prim.shadow.blur_radius == 0.0 {
let picture_prim = &self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0];
let shadow = picture_prim.as_shadow();
if shadow.blur_radius == 0.0 {
let mut text_prim = prim.clone();
if font.render_mode != FontRenderMode::Bitmap {
text_prim.font.color = shadow_prim.shadow.color.into();
}
text_prim.font.color = shadow.color.into();
// If we have translucent text, we need to ensure it won't go
// through the subpixel blend mode, which doesn't work with
// traditional alpha blending.
if shadow_prim.shadow.color.a != 1.0 {
if shadow.color.a != 1.0 {
text_prim.font.render_mode = text_prim.font.render_mode.limit_by(FontRenderMode::Alpha);
}
text_prim.color = shadow_prim.shadow.color;
text_prim.offset += shadow_prim.shadow.offset;
text_prim.offset += shadow.offset;
fast_shadow_prims.push(text_prim);
}
}
@ -1264,18 +1240,19 @@ impl FrameBuilder {
// the indices as sub-primitives to the shadow primitives.
for shadow_prim_index in &self.shadow_prim_stack {
let shadow_metadata = &mut self.prim_store.cpu_metadata[shadow_prim_index.0];
debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Shadow);
let shadow_prim =
&mut self.prim_store.cpu_shadows[shadow_metadata.cpu_prim_index.0];
debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Picture);
let picture_prim =
&mut self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0];
// Only run real blurs here (fast path zero blurs are handled above).
if shadow_prim.shadow.blur_radius > 0.0 {
let blur_radius = picture_prim.as_shadow().blur_radius;
if blur_radius > 0.0 {
let shadow_rect = rect.inflate(
shadow_prim.shadow.blur_radius,
shadow_prim.shadow.blur_radius,
blur_radius,
blur_radius,
);
shadow_metadata.local_rect = shadow_metadata.local_rect.union(&shadow_rect);
shadow_prim.primitives.push(prim_index);
picture_prim.add_primitive(prim_index, clip_and_scroll);
}
}
}

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

@ -13,6 +13,7 @@ pub struct CachedGlyphInfo {
pub glyph_bytes: Arc<Vec<u8>>,
pub size: DeviceUintSize,
pub offset: DevicePoint,
pub scale: f32,
}
pub type GlyphKeyCache = ResourceClassCache<GlyphKey, Option<CachedGlyphInfo>>;

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

@ -3,10 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#[cfg(test)]
use api::{ColorF, FontRenderMode, IdNamespace, LayoutPoint, SubpixelDirection};
use api::{ColorF, IdNamespace, LayoutPoint};
use api::{DevicePoint, DeviceUintSize, FontInstance};
use api::{FontKey, FontTemplate};
use api::{GlyphDimensions, GlyphKey};
use api::{FontKey, FontTemplate, FontRenderMode, ColorU};
use api::{GlyphDimensions, GlyphKey, SubpixelDirection};
use api::{ImageData, ImageDescriptor, ImageFormat};
#[cfg(test)]
use app_units::Au;
@ -144,6 +144,29 @@ impl GlyphRasterizer {
self.fonts_to_remove.push(font_key);
}
pub fn prepare_font(&self, font: &mut FontInstance) {
// In alpha/mono mode, the color of the font is irrelevant.
// Forcing it to black in those cases saves rasterizing glyphs
// of different colors when not needed.
match font.render_mode {
FontRenderMode::Mono | FontRenderMode::Bitmap => {
font.color = ColorU::new(255, 255, 255, 255);
// Subpixel positioning is disabled in mono and bitmap modes.
font.subpx_dir = SubpixelDirection::None;
}
FontRenderMode::Alpha => {
font.color = ColorU::new(255, 255, 255, 255);
}
FontRenderMode::Subpixel => {
// In subpixel mode, we only actually need the color if preblending
// is used in the font backend.
if !FontContext::has_gamma_correct_subpixel_aa() {
font.color = ColorU::new(255, 255, 255, 255);
}
}
}
}
pub fn request_glyphs(
&mut self,
glyph_cache: &mut GlyphCache,
@ -183,7 +206,7 @@ impl GlyphRasterizer {
},
TextureFilter::Linear,
ImageData::Raw(glyph_info.glyph_bytes.clone()),
[glyph_info.offset.x, glyph_info.offset.y],
[glyph_info.offset.x, glyph_info.offset.y, glyph_info.scale],
None,
gpu_cache,
);
@ -246,10 +269,10 @@ impl GlyphRasterizer {
.get_glyph_dimensions(font, glyph_key)
}
pub fn is_bitmap_font(&self, font_key: FontKey) -> bool {
pub fn is_bitmap_font(&self, font: &FontInstance) -> bool {
self.font_contexts
.lock_shared_context()
.is_bitmap_font(font_key)
.is_bitmap_font(font)
}
pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
@ -312,7 +335,7 @@ impl GlyphRasterizer {
},
TextureFilter::Linear,
ImageData::Raw(glyph_bytes.clone()),
[glyph.left, glyph.top],
[glyph.left, glyph.top, glyph.scale],
None,
gpu_cache,
);
@ -321,6 +344,7 @@ impl GlyphRasterizer {
glyph_bytes,
size: DeviceUintSize::new(glyph.width, glyph.height),
offset: DevicePoint::new(glyph.left, glyph.top),
scale: glyph.scale,
})
} else {
None

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

@ -69,6 +69,7 @@ mod glyph_rasterizer;
mod gpu_cache;
mod gpu_types;
mod internal_types;
mod picture;
mod prim_store;
mod print_tree;
mod profiler;

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

@ -0,0 +1,79 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{ClipAndScrollInfo, Shadow};
use prim_store::PrimitiveIndex;
use render_task::RenderTaskId;
/*
A picture represents a dynamically rendered image. It consists of:
* A number of primitives that are drawn onto the picture.
* A composite operation describing how to composite this
picture into its parent.
* A configuration describing how to draw the primitives on
this picture (e.g. in screen space or local space).
*/
#[derive(Clone, Debug)]
pub struct PrimitiveRun {
pub prim_index: PrimitiveIndex,
pub count: usize,
pub clip_and_scroll: ClipAndScrollInfo,
}
#[derive(Debug)]
pub enum CompositeOp {
Shadow(Shadow),
// TODO(gw): Support other composite ops, such
// as blur, blend etc.
}
#[derive(Debug)]
pub struct PicturePrimitive {
pub prim_runs: Vec<PrimitiveRun>,
pub composite_op: CompositeOp,
pub render_task_id: Option<RenderTaskId>,
// TODO(gw): Add a mode that specifies if this
// picture should be rasterized in
// screen-space or local-space.
}
impl PicturePrimitive {
pub fn new_shadow(shadow: Shadow) -> PicturePrimitive {
PicturePrimitive {
prim_runs: Vec::new(),
composite_op: CompositeOp::Shadow(shadow),
render_task_id: None,
}
}
pub fn as_shadow(&self) -> &Shadow {
match self.composite_op {
CompositeOp::Shadow(ref shadow) => shadow,
}
}
pub fn add_primitive(
&mut self,
prim_index: PrimitiveIndex,
clip_and_scroll: ClipAndScrollInfo
) {
if let Some(ref mut run) = self.prim_runs.last_mut() {
if run.clip_and_scroll == clip_and_scroll &&
run.prim_index.0 + run.count == prim_index.0 {
run.count += 1;
return;
}
}
self.prim_runs.push(PrimitiveRun {
prim_index,
count: 1,
clip_and_scroll,
});
}
}

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

@ -42,6 +42,7 @@ pub struct RasterizedGlyph {
pub left: f32,
pub width: u32,
pub height: u32,
pub scale: f32,
pub bytes: Vec<u8>,
}
@ -52,6 +53,7 @@ impl RasterizedGlyph {
left: 0.0,
width: 0,
height: 0,
scale: 1.0,
bytes: vec![],
}
}
@ -422,16 +424,18 @@ impl FontContext {
}
}
pub fn is_bitmap_font(&mut self, font_key: FontKey) -> bool {
match self.get_ct_font(font_key, Au(16 * 60), &[]) {
pub fn is_bitmap_font(&mut self, font: &FontInstance) -> bool {
match self.get_ct_font(font.font_key, font.size, &font.variations) {
Some(ref ct_font) => {
let traits = ct_font.symbolic_traits();
(traits & kCTFontColorGlyphsTrait) != 0
}
None => {
false
None => false,
}
}
pub fn has_gamma_correct_subpixel_aa() -> bool {
true
}
pub fn rasterize_glyph(
@ -585,6 +589,7 @@ impl FontContext {
top: metrics.rasterized_ascent as f32,
width: metrics.rasterized_width,
height: metrics.rasterized_height,
scale: 1.0,
bytes: rasterized_pixels,
})
}

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

@ -3,29 +3,33 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{FontInstance, FontKey, FontRenderMode, GlyphDimensions};
use api::{NativeFontHandle, SubpixelDirection};
use api::GlyphKey;
use api::{FontInstancePlatformOptions, FontLCDFilter, FontHinting};
use api::{NativeFontHandle, SubpixelDirection, GlyphKey};
use api::{FONT_FORCE_AUTOHINT, FONT_NO_AUTOHINT, FONT_EMBEDDED_BITMAP};
use api::{FONT_EMBOLDEN, FONT_VERTICAL_LAYOUT, FONT_SUBPIXEL_BGR};
use freetype::freetype::{FT_BBox, FT_Outline_Translate, FT_Pixel_Mode, FT_Render_Mode};
use freetype::freetype::{FT_Done_Face, FT_Error, FT_Get_Char_Index, FT_Int32};
use freetype::freetype::{FT_Done_FreeType, FT_Library_SetLcdFilter, FT_Pos};
use freetype::freetype::{FT_F26Dot6, FT_Face, FT_Glyph_Format, FT_Long, FT_UInt};
use freetype::freetype::{FT_GlyphSlot, FT_LcdFilter, FT_New_Memory_Face, FT_Outline_Transform};
use freetype::freetype::{FT_GlyphSlot, FT_LcdFilter, FT_New_Memory_Face};
use freetype::freetype::{FT_Init_FreeType, FT_Load_Glyph, FT_Render_Glyph};
use freetype::freetype::{FT_Library, FT_Matrix, FT_Outline_Get_CBox, FT_Set_Char_Size};
use freetype::freetype::{FT_Library, FT_Outline_Get_CBox, FT_Set_Char_Size, FT_Select_Size};
use freetype::freetype::{FT_LOAD_COLOR, FT_LOAD_DEFAULT, FT_LOAD_FORCE_AUTOHINT};
use freetype::freetype::{FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH, FT_LOAD_NO_AUTOHINT};
use freetype::freetype::{FT_LOAD_NO_BITMAP, FT_LOAD_NO_HINTING, FT_LOAD_VERTICAL_LAYOUT};
use freetype::freetype::{FT_FACE_FLAG_SCALABLE, FT_FACE_FLAG_FIXED_SIZES, FT_Err_Cannot_Render_Glyph};
use internal_types::FastHashMap;
use std::{mem, ptr, slice};
use std::{cmp, mem, ptr, slice};
use std::sync::Arc;
// This constant is not present in the freetype
// These constants are not present in the freetype
// bindings due to bindgen not handling the way
// the macro is defined.
const FT_LOAD_TARGET_LIGHT: FT_Int32 = 1 << 16;
// Default to slight hinting, which is what most
// Linux distros use by default, and is a better
// default than no hinting.
// TODO(gw): Make this configurable.
const GLYPH_LOAD_FLAGS: FT_Int32 = FT_LOAD_TARGET_LIGHT;
// the macros are defined.
//const FT_LOAD_TARGET_NORMAL: FT_UInt = 0 << 16;
const FT_LOAD_TARGET_LIGHT: FT_UInt = 1 << 16;
const FT_LOAD_TARGET_MONO: FT_UInt = 2 << 16;
const FT_LOAD_TARGET_LCD: FT_UInt = 3 << 16;
const FT_LOAD_TARGET_LCD_V: FT_UInt = 4 << 16;
struct Face {
face: FT_Face,
@ -50,17 +54,25 @@ pub struct RasterizedGlyph {
pub left: f32,
pub width: u32,
pub height: u32,
pub scale: f32,
pub bytes: Vec<u8>,
}
const SUCCESS: FT_Error = FT_Error(0);
extern "C" {
fn FT_GlyphSlot_Embolden(slot: FT_GlyphSlot);
fn FT_GlyphSlot_Oblique(slot: FT_GlyphSlot);
}
impl FontContext {
pub fn new() -> FontContext {
let mut lib: FT_Library = ptr::null_mut();
// Per Skia, using a filter adds one full pixel to each side.
let mut lcd_extra_pixels = 1;
// Using an LCD filter may add one full pixel to each side if support is built in.
// As of FreeType 2.8.1, an LCD filter is always used regardless of settings
// if support for the patent-encumbered LCD filter algorithms is not built in.
// Thus, the only reasonable way to guess padding is to unconditonally add it if
// subpixel AA is used.
let lcd_extra_pixels = 1;
unsafe {
let result = FT_Init_FreeType(&mut lib);
@ -69,22 +81,12 @@ impl FontContext {
"Unable to initialize FreeType library {:?}",
result
);
// TODO(gw): Check result of this to determine if freetype build supports subpixel.
let result = FT_Library_SetLcdFilter(lib, FT_LcdFilter::FT_LCD_FILTER_DEFAULT);
if !result.succeeded() {
println!(
"WARN: Initializing a FreeType library build without subpixel AA enabled!"
);
lcd_extra_pixels = 0;
}
}
FontContext {
lib,
faces: FastHashMap::default(),
lcd_extra_pixels: lcd_extra_pixels,
lcd_extra_pixels,
}
}
@ -132,25 +134,71 @@ impl FontContext {
fn load_glyph(&self, font: &FontInstance, glyph: &GlyphKey) -> Option<FT_GlyphSlot> {
debug_assert!(self.faces.contains_key(&font.font_key));
let face = self.faces.get(&font.font_key).unwrap();
let mut load_flags = FT_LOAD_DEFAULT;
let FontInstancePlatformOptions { flags, hinting, .. } = font.platform_options.unwrap_or_default();
match (hinting, font.render_mode) {
(FontHinting::None, _) => load_flags |= FT_LOAD_NO_HINTING,
(FontHinting::Mono, _) => load_flags = FT_LOAD_TARGET_MONO,
(FontHinting::Light, _) => load_flags = FT_LOAD_TARGET_LIGHT,
(FontHinting::LCD, FontRenderMode::Subpixel) => {
load_flags = match font.subpx_dir {
SubpixelDirection::Vertical => FT_LOAD_TARGET_LCD_V,
_ => FT_LOAD_TARGET_LCD,
};
if (flags & FONT_FORCE_AUTOHINT) != 0 {
load_flags |= FT_LOAD_FORCE_AUTOHINT;
}
}
_ => {
if (flags & FONT_FORCE_AUTOHINT) != 0 {
load_flags |= FT_LOAD_FORCE_AUTOHINT;
}
}
}
if (flags & FONT_NO_AUTOHINT) != 0 {
load_flags |= FT_LOAD_NO_AUTOHINT;
}
if (flags & FONT_EMBEDDED_BITMAP) == 0 {
load_flags |= FT_LOAD_NO_BITMAP;
}
if (flags & FONT_VERTICAL_LAYOUT) != 0 {
load_flags |= FT_LOAD_VERTICAL_LAYOUT;
}
load_flags |= FT_LOAD_COLOR;
load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
let mut result = if font.render_mode == FontRenderMode::Bitmap {
if (load_flags & FT_LOAD_NO_BITMAP) != 0 {
FT_Error(FT_Err_Cannot_Render_Glyph as i32)
} else {
self.choose_bitmap_size(face.face, font.size.to_f64_px())
}
} else {
let char_size = font.size.to_f64_px() * 64.0 + 0.5;
unsafe { FT_Set_Char_Size(face.face, char_size as FT_F26Dot6, 0, 0, 0) }
};
assert_eq!(SUCCESS, unsafe {
FT_Set_Char_Size(face.face, char_size as FT_F26Dot6, 0, 0, 0)
});
if result.succeeded() {
result = unsafe { FT_Load_Glyph(face.face, glyph.index as FT_UInt, load_flags as FT_Int32) };
};
let result = unsafe { FT_Load_Glyph(face.face, glyph.index as FT_UInt, GLYPH_LOAD_FLAGS) };
if result == SUCCESS {
if result.succeeded() {
let slot = unsafe { (*face.face).glyph };
assert!(slot != ptr::null_mut());
// TODO(gw): We use the FT_Outline_* APIs to manage sub-pixel offsets.
// We will need a custom code path for bitmap fonts (which
// are very rare).
match unsafe { (*slot).format } {
FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => Some(slot),
if (flags & FONT_EMBOLDEN) != 0 {
unsafe { FT_GlyphSlot_Embolden(slot) };
}
let format = unsafe { (*slot).format };
match format {
FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE |
FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => Some(slot),
_ => {
error!("TODO: Support bitmap fonts!");
error!("Unsupported {:?}", format);
None
}
}
@ -178,6 +226,11 @@ impl FontContext {
// Get the estimated bounding box from FT (control points).
unsafe {
FT_Outline_Get_CBox(&(*slot).outline, &mut cbox);
// For spaces and other non-printable characters, early out.
if (*slot).outline.n_contours == 0 {
return cbox;
}
}
// Convert the subpixel offset to floats.
@ -185,13 +238,11 @@ impl FontContext {
// Apply extra pixel of padding for subpixel AA, due to the filter.
let padding = match font.render_mode {
FontRenderMode::Subpixel => self.lcd_extra_pixels * 64,
FontRenderMode::Subpixel => (self.lcd_extra_pixels * 64) as FT_Pos,
FontRenderMode::Alpha |
FontRenderMode::Mono |
FontRenderMode::Bitmap => 0,
FontRenderMode::Bitmap => 0 as FT_Pos,
};
cbox.xMin -= padding as FT_Pos;
cbox.xMax += padding as FT_Pos;
// Offset the bounding box by subpixel positioning.
// Convert to 26.6 fixed point format for FT.
@ -199,13 +250,13 @@ impl FontContext {
SubpixelDirection::None => {}
SubpixelDirection::Horizontal => {
let dx = (dx * 64.0 + 0.5) as FT_Long;
cbox.xMin += dx;
cbox.xMax += dx;
cbox.xMin += dx - padding;
cbox.xMax += dx + padding;
}
SubpixelDirection::Vertical => {
let dy = (dy * 64.0 + 0.5) as FT_Long;
cbox.yMin += dy;
cbox.yMax += dy;
cbox.yMin += dy - padding;
cbox.yMax += dy + padding;
}
}
@ -223,24 +274,59 @@ impl FontContext {
slot: FT_GlyphSlot,
font: &FontInstance,
glyph: &GlyphKey,
scale_bitmaps: bool,
) -> Option<GlyphDimensions> {
let metrics = unsafe { &(*slot).metrics };
// If there's no advance, no need to consider this glyph
// for layout.
if metrics.horiAdvance == 0 {
None
} else {
let cbox = self.get_bounding_box(slot, font, glyph);
return None
}
let advance = metrics.horiAdvance as f32 / 64.0;
match unsafe { (*slot).format } {
FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
let left = unsafe { (*slot).bitmap_left };
let top = unsafe { (*slot).bitmap_top };
let width = unsafe { (*slot).bitmap.width };
let height = unsafe { (*slot).bitmap.rows };
if scale_bitmaps {
let y_size = unsafe { (*(*(*slot).face).size).metrics.y_ppem };
let scale = font.size.to_f32_px() / y_size as f32;
let x0 = left as f32 * scale;
let x1 = width as f32 * scale + x0;
let y1 = top as f32 * scale;
let y0 = y1 - height as f32 * scale;
Some(GlyphDimensions {
left: x0.round() as i32,
top: y1.round() as i32,
width: (x1.ceil() - x0.floor()) as u32,
height: (y1.ceil() - y0.floor()) as u32,
advance: advance * scale,
})
} else {
Some(GlyphDimensions {
left,
top,
width,
height,
advance,
})
}
}
FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
let cbox = self.get_bounding_box(slot, font, glyph);
Some(GlyphDimensions {
left: (cbox.xMin >> 6) as i32,
top: (cbox.yMax >> 6) as i32,
width: ((cbox.xMax - cbox.xMin) >> 6) as u32,
height: ((cbox.yMax - cbox.yMin) >> 6) as u32,
advance: metrics.horiAdvance as f32 / 64.0,
advance,
})
}
_ => None,
}
}
pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
@ -261,42 +347,54 @@ impl FontContext {
key: &GlyphKey,
) -> Option<GlyphDimensions> {
let slot = self.load_glyph(font, key);
slot.and_then(|slot| self.get_glyph_dimensions_impl(slot, font, key))
slot.and_then(|slot| self.get_glyph_dimensions_impl(slot, font, key, true))
}
pub fn is_bitmap_font(&mut self, _font_key: FontKey) -> bool {
// TODO(gw): Support bitmap fonts in Freetype.
pub fn is_bitmap_font(&mut self, font: &FontInstance) -> bool {
debug_assert!(self.faces.contains_key(&font.font_key));
let face = self.faces.get(&font.font_key).unwrap();
let face_flags = unsafe { (*face.face).face_flags };
// If the face has embedded bitmaps, they should only be used if either
// embedded bitmaps are explicitly requested or if the face has no outline.
if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 {
let FontInstancePlatformOptions { flags, .. } = font.platform_options.unwrap_or_default();
if (flags & FONT_EMBEDDED_BITMAP) != 0 {
return true;
}
(face_flags & (FT_FACE_FLAG_SCALABLE as FT_Long)) == 0
} else {
false
}
}
fn choose_bitmap_size(&self, face: FT_Face, requested_size: f64) -> FT_Error {
let mut best_dist = unsafe { *(*face).available_sizes.offset(0) }.y_ppem as f64 / 64.0 - requested_size;
let mut best_size = 0;
let num_fixed_sizes = unsafe { (*face).num_fixed_sizes };
for i in 1 .. num_fixed_sizes {
// Distance is positive if strike is larger than desired size,
// or negative if smaller. If previously a found smaller strike,
// then prefer a larger strike. Otherwise, minimize distance.
let dist = unsafe { *(*face).available_sizes.offset(i as isize) }.y_ppem as f64 / 64.0 - requested_size;
if (best_dist < 0.0 && dist >= best_dist) || dist.abs() <= best_dist {
best_dist = dist;
best_size = i;
}
}
unsafe { FT_Select_Size(face, best_size) }
}
pub fn has_gamma_correct_subpixel_aa() -> bool {
// We don't do any preblending with FreeType currently, so the color is not used.
false
}
pub fn rasterize_glyph(
fn rasterize_glyph_outline(
&mut self,
slot: FT_GlyphSlot,
font: &FontInstance,
key: &GlyphKey,
) -> Option<RasterizedGlyph> {
let slot = match self.load_glyph(font, key) {
Some(slot) => slot,
None => return None,
};
let render_mode = match font.render_mode {
FontRenderMode::Mono => FT_Render_Mode::FT_RENDER_MODE_MONO,
FontRenderMode::Alpha => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
FontRenderMode::Subpixel => FT_Render_Mode::FT_RENDER_MODE_LCD,
FontRenderMode::Bitmap => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
};
// Get dimensions of the glyph, to see if we need to rasterize it.
let dimensions = match self.get_glyph_dimensions_impl(slot, font, key) {
Some(val) => val,
None => return None,
};
// For spaces and other non-printable characters, early out.
if dimensions.width == 0 || dimensions.height == 0 {
return None;
}
) -> bool {
// Get the subpixel offsets in FT 26.6 format.
let (dx, dy) = font.get_subpx_offset(key);
let dx = (dx * 64.0 + 0.5) as FT_Long;
@ -315,93 +413,204 @@ impl FontContext {
);
if font.synthetic_italics {
// These magic numbers are pre-encoded fixed point
// values that apply ~12 degree shear. Borrowed
// from the Freetype implementation of the
// FT_GlyphSlot_Oblique function.
let transform = FT_Matrix {
xx: 0x10000,
yx: 0x00000,
xy: 0x0366A,
yy: 0x10000,
};
FT_Outline_Transform(outline, &transform);
FT_GlyphSlot_Oblique(slot);
}
}
if font.render_mode == FontRenderMode::Subpixel {
let FontInstancePlatformOptions { lcd_filter, .. } = font.platform_options.unwrap_or_default();
let filter = match lcd_filter {
FontLCDFilter::None => FT_LcdFilter::FT_LCD_FILTER_NONE,
FontLCDFilter::Default => FT_LcdFilter::FT_LCD_FILTER_DEFAULT,
FontLCDFilter::Light => FT_LcdFilter::FT_LCD_FILTER_LIGHT,
FontLCDFilter::Legacy => FT_LcdFilter::FT_LCD_FILTER_LEGACY,
};
unsafe { FT_Library_SetLcdFilter(self.lib, filter) };
}
let render_mode = match (font.render_mode, font.subpx_dir) {
(FontRenderMode::Mono, _) => FT_Render_Mode::FT_RENDER_MODE_MONO,
(FontRenderMode::Alpha, _) | (FontRenderMode::Bitmap, _) => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
(FontRenderMode::Subpixel, SubpixelDirection::Vertical) => FT_Render_Mode::FT_RENDER_MODE_LCD_V,
(FontRenderMode::Subpixel, _) => FT_Render_Mode::FT_RENDER_MODE_LCD,
};
let result = unsafe { FT_Render_Glyph(slot, render_mode) };
if result != SUCCESS {
if !result.succeeded() {
error!(
"Unable to rasterize {:?} with {:?}, {:?}",
key,
render_mode,
result
);
false
} else {
true
}
}
pub fn rasterize_glyph(
&mut self,
font: &FontInstance,
key: &GlyphKey,
) -> Option<RasterizedGlyph> {
let slot = match self.load_glyph(font, key) {
Some(slot) => slot,
None => return None,
};
// Get dimensions of the glyph, to see if we need to rasterize it.
let dimensions = match self.get_glyph_dimensions_impl(slot, font, key, false) {
Some(val) => val,
None => return None,
};
// For spaces and other non-printable characters, early out.
if dimensions.width == 0 || dimensions.height == 0 {
return None;
}
let format = unsafe { (*slot).format };
let mut scale = 1.0;
match format {
FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
let y_size = unsafe { (*(*(*slot).face).size).metrics.y_ppem };
scale = font.size.to_f32_px() / y_size as f32;
}
FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
if !self.rasterize_glyph_outline(slot, font, key) {
return None;
}
}
_ => {
error!("Unsupported {:?}", format);
return None;
}
}
let bitmap = unsafe { &(*slot).bitmap };
let pixel_mode = unsafe { mem::transmute(bitmap.pixel_mode as u32) };
info!(
"Rasterizing {:?} as {:?} with dimensions {:?}",
key,
render_mode,
font.render_mode,
dimensions
);
let actual_width = match pixel_mode {
let (actual_width, actual_height) = match pixel_mode {
FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
assert!(bitmap.width % 3 == 0);
bitmap.width / 3
((bitmap.width / 3) as i32, bitmap.rows as i32)
}
FT_Pixel_Mode::FT_PIXEL_MODE_MONO | FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => bitmap.width,
_ => {
panic!("Unexpected pixel mode!");
FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V => {
assert!(bitmap.rows % 3 == 0);
(bitmap.width as i32, (bitmap.rows / 3) as i32)
}
} as i32;
let actual_height = bitmap.rows as i32;
let top = unsafe { (*slot).bitmap_top };
let left = unsafe { (*slot).bitmap_left };
FT_Pixel_Mode::FT_PIXEL_MODE_MONO | FT_Pixel_Mode::FT_PIXEL_MODE_GRAY | FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
(bitmap.width as i32, bitmap.rows as i32)
}
_ => panic!("Unsupported {:?}", pixel_mode),
};
let (left, top) = unsafe { ((*slot).bitmap_left, (*slot).bitmap_top) };
let mut final_buffer = vec![0; (actual_width * actual_height * 4) as usize];
// Extract the final glyph from FT format into RGBA8 format, which is
// what WR expects.
for y in 0 .. actual_height {
// Get pointer to the bytes for this row.
let mut src = unsafe { bitmap.buffer.offset((y * bitmap.pitch) as isize) };
for x in 0 .. actual_width {
let value = match pixel_mode {
let FontInstancePlatformOptions { flags, .. } = font.platform_options.unwrap_or_default();
let subpixel_bgr = (flags & FONT_SUBPIXEL_BGR) != 0;
let mut src_row = bitmap.buffer;
let mut dest: usize = 0;
while dest < final_buffer.len() {
let mut src = src_row;
let row_end = dest + actual_width as usize * 4;
match pixel_mode {
FT_Pixel_Mode::FT_PIXEL_MODE_MONO => {
let mask = 0x80 >> (x & 0x7);
let byte = unsafe { *src.offset((x >> 3) as isize) };
let alpha = if byte & mask != 0 { 0xff } else { 0 };
[0xff, 0xff, 0xff, alpha]
while dest < row_end {
// Cast the byte to signed so that we can left shift each bit into
// the top bit, then right shift to fill out the bits with 0s or 1s.
let mut byte: i8 = unsafe { *src as i8 };
src = unsafe { src.offset(1) };
let byte_end = cmp::min(row_end, dest + 8 * 4);
while dest < byte_end {
let alpha = (byte >> 7) as u8;
final_buffer[dest + 0] = alpha;
final_buffer[dest + 1] = alpha;
final_buffer[dest + 2] = alpha;
final_buffer[dest + 3] = alpha;
dest += 4;
byte <<= 1;
}
}
}
FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => {
while dest < row_end {
let alpha = unsafe { *src };
final_buffer[dest + 0] = alpha;
final_buffer[dest + 1] = alpha;
final_buffer[dest + 2] = alpha;
final_buffer[dest + 3] = alpha;
src = unsafe { src.offset(1) };
[0xff, 0xff, 0xff, alpha]
dest += 4;
}
}
FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
let t = unsafe { slice::from_raw_parts(src, 3) };
if subpixel_bgr {
while dest < row_end {
final_buffer[dest + 0] = unsafe { *src };
final_buffer[dest + 1] = unsafe { *src.offset(1) };
final_buffer[dest + 2] = unsafe { *src.offset(2) };
final_buffer[dest + 3] = 0xff;
src = unsafe { src.offset(3) };
[t[2], t[1], t[0], 0xff]
dest += 4;
}
} else {
while dest < row_end {
final_buffer[dest + 2] = unsafe { *src };
final_buffer[dest + 1] = unsafe { *src.offset(1) };
final_buffer[dest + 0] = unsafe { *src.offset(2) };
final_buffer[dest + 3] = 0xff;
src = unsafe { src.offset(3) };
dest += 4;
}
}
}
FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V => {
if subpixel_bgr {
while dest < row_end {
final_buffer[dest + 0] = unsafe { *src };
final_buffer[dest + 1] = unsafe { *src.offset(bitmap.pitch as isize) };
final_buffer[dest + 2] = unsafe { *src.offset((2 * bitmap.pitch) as isize) };
final_buffer[dest + 3] = 0xff;
src = unsafe { src.offset(1) };
dest += 4;
}
} else {
while dest < row_end {
final_buffer[dest + 2] = unsafe { *src };
final_buffer[dest + 1] = unsafe { *src.offset(bitmap.pitch as isize) };
final_buffer[dest + 0] = unsafe { *src.offset((2 * bitmap.pitch) as isize) };
final_buffer[dest + 3] = 0xff;
src = unsafe { src.offset(1) };
dest += 4;
}
}
src_row = unsafe { src_row.offset((2 * bitmap.pitch) as isize) };
}
FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
// The source is premultiplied BGRA data.
let dest_slice = &mut final_buffer[dest .. row_end];
let src_slice = unsafe { slice::from_raw_parts(src, dest_slice.len()) };
dest_slice.copy_from_slice(src_slice);
}
_ => panic!("Unsupported {:?}", pixel_mode),
};
let i = 4 * (y * actual_width + x) as usize;
let dest = &mut final_buffer[i .. i + 4];
dest.clone_from_slice(&value);
}
src_row = unsafe { src_row.offset(bitmap.pitch as isize) };
}
Some(RasterizedGlyph {
left: (dimensions.left + left) as f32,
top: (dimensions.top + top - actual_height) as f32,
left: ((dimensions.left + left) as f32 * scale).round(),
top: ((dimensions.top + top - actual_height) as f32 * scale).round(),
width: actual_width as u32,
height: actual_height as u32,
scale,
bytes: final_buffer,
})
}

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

@ -33,6 +33,7 @@ pub struct RasterizedGlyph {
pub left: f32,
pub width: u32,
pub height: u32,
pub scale: f32,
pub bytes: Vec<u8>,
}
@ -304,11 +305,15 @@ impl FontContext {
}
}
pub fn is_bitmap_font(&mut self, _font_key: FontKey) -> bool {
pub fn is_bitmap_font(&mut self, _font: &FontInstance) -> bool {
// TODO(gw): Support bitmap fonts in DWrite.
false
}
pub fn has_gamma_correct_subpixel_aa() -> bool {
true
}
pub fn rasterize_glyph(
&mut self,
font: &FontInstance,
@ -329,7 +334,9 @@ impl FontContext {
let mut pixels = analysis.create_alpha_texture(texture_type, bounds);
if font.render_mode != FontRenderMode::Mono {
match font.render_mode {
FontRenderMode::Mono | FontRenderMode::Bitmap => {}
FontRenderMode::Alpha | FontRenderMode::Subpixel => {
let lut_correction = match font.platform_options {
Some(option) => if option.force_gdi_rendering {
&self.gdi_gamma_lut
@ -346,6 +353,7 @@ impl FontContext {
ColorLut::new(font.color.r, font.color.g, font.color.b, font.color.a),
);
}
}
let rgba_pixels = self.convert_to_rgba(&mut pixels, font.render_mode);
@ -354,6 +362,7 @@ impl FontContext {
top: -bounds.top as f32,
width: width as u32,
height: height as u32,
scale: 1.0,
bytes: rgba_pixels,
})
}

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

@ -5,7 +5,7 @@
use api::{BorderRadius, BuiltDisplayList, ColorF, ComplexClipRegion, DeviceIntRect, DeviceIntSize};
use api::{DevicePoint, ExtendMode, FontInstance, FontRenderMode, GlyphInstance, GlyphKey};
use api::{GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerRect};
use api::{LayerSize, LayerVector2D, LineOrientation, LineStyle, Shadow};
use api::{LayerSize, LayerVector2D, LineOrientation, LineStyle};
use api::{TileOffset, YuvColorSpace, YuvFormat, device_length};
use app_units::Au;
use border::BorderCornerInstance;
@ -14,6 +14,7 @@ use euclid::Size2D;
use frame_builder::PrimitiveContext;
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
ToGpuBlocks};
use picture::PicturePrimitive;
use render_task::{ClipWorkItem, RenderTask, RenderTaskId, RenderTaskTree};
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
use resource_cache::{ImageProperties, ResourceCache};
@ -110,8 +111,8 @@ pub enum PrimitiveKind {
AngleGradient,
RadialGradient,
BoxShadow,
Shadow,
Line,
Picture,
}
impl GpuCacheHandle {
@ -514,13 +515,6 @@ impl RadialGradientPrimitiveCpu {
}
}
#[derive(Debug)]
pub struct ShadowPrimitiveCpu {
pub shadow: Shadow,
pub primitives: Vec<PrimitiveIndex>,
pub render_task_id: Option<RenderTaskId>,
}
#[derive(Debug, Clone)]
pub struct TextRunPrimitiveCpu {
pub font: FontInstance,
@ -529,8 +523,6 @@ pub struct TextRunPrimitiveCpu {
pub glyph_count: usize,
pub glyph_keys: Vec<GlyphKey>,
pub glyph_gpu_blocks: Vec<GpuBlockData>,
pub shadow_render_mode: FontRenderMode,
pub color: ColorF,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
@ -540,6 +532,23 @@ pub enum TextRunMode {
}
impl TextRunPrimitiveCpu {
pub fn get_font(&self,
run_mode: TextRunMode,
device_pixel_ratio: f32,
) -> FontInstance {
let mut font = self.font.clone();
match run_mode {
TextRunMode::Normal => {}
TextRunMode::Shadow => {
// Shadows never use subpixel AA, but need to respect the alpha/mono flag
// for reftests.
font.render_mode = font.render_mode.limit_by(FontRenderMode::Alpha);
}
};
font.size = font.size.scale_by(device_pixel_ratio);
font
}
fn prepare_for_render(
&mut self,
resource_cache: &mut ResourceCache,
@ -548,33 +557,22 @@ impl TextRunPrimitiveCpu {
run_mode: TextRunMode,
gpu_cache: &mut GpuCache,
) {
let mut font = self.font.clone();
font.size = font.size.scale_by(device_pixel_ratio);
match run_mode {
TextRunMode::Shadow => {
font.render_mode = self.shadow_render_mode;
}
TextRunMode::Normal => {}
}
if run_mode == TextRunMode::Shadow {
font.render_mode = self.shadow_render_mode;
}
let font = self.get_font(run_mode, device_pixel_ratio);
// Cache the glyph positions, if not in the cache already.
// TODO(gw): In the future, remove `glyph_instances`
// completely, and just reference the glyphs
// directly from the display list.
if self.glyph_keys.is_empty() {
let subpx_dir = font.subpx_dir.limit_by(font.render_mode);
let src_glyphs = display_list.get(self.glyph_range);
// TODO(gw): If we support chunks() on AuxIter
// in the future, this code below could
// be much simpler...
let mut gpu_block = GpuBlockData::empty();
for (i, src) in src_glyphs.enumerate() {
let key = GlyphKey::new(src.index, src.point, font.render_mode, font.subpx_dir);
let key = GlyphKey::new(src.index, src.point, font.render_mode, subpx_dir);
self.glyph_keys.push(key);
// Two glyphs are packed per GPU block.
@ -600,11 +598,11 @@ impl TextRunPrimitiveCpu {
}
fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
request.push(self.color);
request.push(ColorF::from(self.font.color));
request.push([
self.offset.x,
self.offset.y,
self.font.subpx_dir as u32 as f32,
self.font.subpx_dir.limit_by(self.font.render_mode) as u32 as f32,
0.0,
]);
request.extend_from_slice(&self.glyph_gpu_blocks);
@ -807,7 +805,7 @@ pub enum PrimitiveContainer {
AngleGradient(GradientPrimitiveCpu),
RadialGradient(RadialGradientPrimitiveCpu),
BoxShadow(BoxShadowPrimitiveCpu),
Shadow(ShadowPrimitiveCpu),
Picture(PicturePrimitive),
Line(LinePrimitive),
}
@ -815,7 +813,7 @@ pub struct PrimitiveStore {
/// CPU side information only.
pub cpu_rectangles: Vec<RectanglePrimitive>,
pub cpu_text_runs: Vec<TextRunPrimitiveCpu>,
pub cpu_shadows: Vec<ShadowPrimitiveCpu>,
pub cpu_pictures: Vec<PicturePrimitive>,
pub cpu_images: Vec<ImagePrimitiveCpu>,
pub cpu_yuv_images: Vec<YuvImagePrimitiveCpu>,
pub cpu_gradients: Vec<GradientPrimitiveCpu>,
@ -832,7 +830,7 @@ impl PrimitiveStore {
cpu_metadata: Vec::new(),
cpu_rectangles: Vec::new(),
cpu_text_runs: Vec::new(),
cpu_shadows: Vec::new(),
cpu_pictures: Vec::new(),
cpu_images: Vec::new(),
cpu_yuv_images: Vec::new(),
cpu_gradients: Vec::new(),
@ -848,7 +846,7 @@ impl PrimitiveStore {
cpu_metadata: recycle_vec(self.cpu_metadata),
cpu_rectangles: recycle_vec(self.cpu_rectangles),
cpu_text_runs: recycle_vec(self.cpu_text_runs),
cpu_shadows: recycle_vec(self.cpu_shadows),
cpu_pictures: recycle_vec(self.cpu_pictures),
cpu_images: recycle_vec(self.cpu_images),
cpu_yuv_images: recycle_vec(self.cpu_yuv_images),
cpu_gradients: recycle_vec(self.cpu_gradients),
@ -920,15 +918,15 @@ impl PrimitiveStore {
self.cpu_text_runs.push(text_cpu);
metadata
}
PrimitiveContainer::Shadow(shadow) => {
PrimitiveContainer::Picture(picture) => {
let metadata = PrimitiveMetadata {
opacity: PrimitiveOpacity::translucent(),
prim_kind: PrimitiveKind::Shadow,
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_shadows.len()),
prim_kind: PrimitiveKind::Picture,
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_pictures.len()),
..base_metadata
};
self.cpu_shadows.push(shadow);
self.cpu_pictures.push(picture);
metadata
}
PrimitiveContainer::Image(image_cpu) => {
@ -1035,9 +1033,9 @@ impl PrimitiveStore {
let box_shadow = &self.cpu_box_shadows[metadata.cpu_prim_index.0];
box_shadow.render_task_id
}
PrimitiveKind::Shadow => {
let shadow = &self.cpu_shadows[metadata.cpu_prim_index.0];
shadow.render_task_id
PrimitiveKind::Picture => {
let picture = &self.cpu_pictures[metadata.cpu_prim_index.0];
picture.render_task_id
}
PrimitiveKind::Rectangle |
PrimitiveKind::TextRun |
@ -1114,8 +1112,8 @@ impl PrimitiveStore {
// ignore the new task if we are in a dependency context
box_shadow.render_task_id = render_tasks.map(|rt| rt.add(render_task));
}
PrimitiveKind::Shadow => {
let shadow = &mut self.cpu_shadows[metadata.cpu_prim_index.0];
PrimitiveKind::Picture => {
let picture = &mut self.cpu_pictures[metadata.cpu_prim_index.0];
// This is a shadow element. Create a render task that will
// render the text run to a target, and then apply a gaussian
@ -1126,14 +1124,15 @@ impl PrimitiveStore {
let cache_height =
(metadata.local_rect.size.height * prim_context.device_pixel_ratio).ceil() as i32;
let cache_size = DeviceIntSize::new(cache_width, cache_height);
let blur_radius = device_length(shadow.shadow.blur_radius, prim_context.device_pixel_ratio);
let blur_radius = picture.as_shadow().blur_radius;
let blur_radius = device_length(blur_radius, prim_context.device_pixel_ratio);
// ignore new tasks if we are in a dependency context
shadow.render_task_id = render_tasks.map(|rt| {
let prim_cache_task = RenderTask::new_prim_cache(cache_size, prim_index);
let prim_cache_task_id = rt.add(prim_cache_task);
picture.render_task_id = render_tasks.map(|rt| {
let picture_task = RenderTask::new_picture(cache_size, prim_index);
let picture_task_id = rt.add(picture_task);
let render_task =
RenderTask::new_blur(blur_radius, prim_cache_task_id, rt);
RenderTask::new_blur(blur_radius, picture_task_id, rt);
rt.add(render_task)
});
}
@ -1234,13 +1233,14 @@ impl PrimitiveStore {
let text = &self.cpu_text_runs[metadata.cpu_prim_index.0];
text.write_gpu_blocks(&mut request);
}
PrimitiveKind::Shadow => {
let prim = &self.cpu_shadows[metadata.cpu_prim_index.0];
request.push(prim.shadow.color);
PrimitiveKind::Picture => {
let picture = &self.cpu_pictures[metadata.cpu_prim_index.0];
let shadow = picture.as_shadow();
request.push(shadow.color);
request.push([
prim.shadow.offset.x,
prim.shadow.offset.y,
prim.shadow.blur_radius,
shadow.offset.x,
shadow.offset.y,
shadow.blur_radius,
0.0,
]);
}
@ -1374,8 +1374,8 @@ impl PrimitiveStore {
};
let dependencies = match metadata.prim_kind {
PrimitiveKind::Shadow =>
self.cpu_shadows[metadata.cpu_prim_index.0].primitives.clone(),
PrimitiveKind::Picture =>
self.cpu_pictures[metadata.cpu_prim_index.0].prim_runs.clone(),
_ => Vec::new(),
};
(geometry, dependencies)
@ -1386,7 +1386,10 @@ impl PrimitiveStore {
// Specifically, the clone() below on the primitive list for
// text shadow primitives. Consider restructuring this code to
// avoid borrow checker issues.
for sub_prim_index in dependent_primitives {
for run in dependent_primitives {
for i in 0 .. run.count {
let sub_prim_index = PrimitiveIndex(run.prim_index.0 + i);
self.prepare_prim_for_render_inner(
sub_prim_index,
prim_context,
@ -1396,6 +1399,7 @@ impl PrimitiveStore {
TextRunMode::Shadow,
);
}
}
if !self.update_clip_task(
prim_index,

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

@ -712,8 +712,6 @@ impl ToDebugString for SpecificDisplayItem {
SpecificDisplayItem::Clip(..) => String::from("clip"),
SpecificDisplayItem::ScrollFrame(..) => String::from("scroll_frame"),
SpecificDisplayItem::StickyFrame(..) => String::from("sticky_frame"),
SpecificDisplayItem::PushNestedDisplayList => String::from("push_nested_display_list"),
SpecificDisplayItem::PopNestedDisplayList => String::from("pop_nested_display_list"),
SpecificDisplayItem::SetGradientStops => String::from("set_gradient_stops"),
SpecificDisplayItem::PopStackingContext => String::from("pop_stacking_context"),
SpecificDisplayItem::PushShadow(..) => String::from("push_shadow"),

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

@ -226,7 +226,7 @@ pub struct RenderTaskData {
#[derive(Debug)]
pub enum RenderTaskKind {
Alpha(AlphaRenderTask),
CachePrimitive(PrimitiveIndex),
Picture(PrimitiveIndex),
BoxShadow(PrimitiveIndex),
CacheMask(CacheMaskTask),
VerticalBlur(DeviceIntLength),
@ -269,12 +269,12 @@ impl RenderTask {
Self::new_alpha_batch(rect.origin, location, frame_output_pipeline_id)
}
pub fn new_prim_cache(size: DeviceIntSize, prim_index: PrimitiveIndex) -> RenderTask {
pub fn new_picture(size: DeviceIntSize, prim_index: PrimitiveIndex) -> RenderTask {
RenderTask {
cache_key: None,
children: Vec::new(),
location: RenderTaskLocation::Dynamic(None, size),
kind: RenderTaskKind::CachePrimitive(prim_index),
kind: RenderTaskKind::Picture(prim_index),
}
}
@ -329,7 +329,10 @@ impl RenderTask {
}
match clip_info.bounds.inner {
Some(ref inner) if !inner.device_rect.is_empty() => {
// Inner rects aren't valid if the item is not axis-aligned, which can
// be determined by the apply_rectangles field. This is mostly a band-aid
// until we have better handling of inner rectangles for transformed clips.
Some(ref inner) if !work_item.apply_rectangles && !inner.device_rect.is_empty() => {
inner_rect = inner_rect.and_then(|r| r.intersection(&inner.device_rect));
!inner.device_rect.contains_rect(&task_rect)
}
@ -423,7 +426,7 @@ impl RenderTask {
pub fn as_alpha_batch_mut<'a>(&'a mut self) -> &'a mut AlphaRenderTask {
match self.kind {
RenderTaskKind::Alpha(ref mut task) => task,
RenderTaskKind::CachePrimitive(..) |
RenderTaskKind::Picture(..) |
RenderTaskKind::BoxShadow(..) |
RenderTaskKind::CacheMask(..) |
RenderTaskKind::VerticalBlur(..) |
@ -436,7 +439,7 @@ impl RenderTask {
pub fn as_alpha_batch<'a>(&'a self) -> &'a AlphaRenderTask {
match self.kind {
RenderTaskKind::Alpha(ref task) => task,
RenderTaskKind::CachePrimitive(..) |
RenderTaskKind::Picture(..) |
RenderTaskKind::BoxShadow(..) |
RenderTaskKind::CacheMask(..) |
RenderTaskKind::VerticalBlur(..) |
@ -478,7 +481,7 @@ impl RenderTask {
],
}
}
RenderTaskKind::CachePrimitive(..) | RenderTaskKind::BoxShadow(..) => {
RenderTaskKind::Picture(..) | RenderTaskKind::BoxShadow(..) => {
let (target_rect, target_index) = self.get_target_rect();
RenderTaskData {
data: [
@ -580,7 +583,7 @@ impl RenderTask {
pub fn target_kind(&self) -> RenderTargetKind {
match self.kind {
RenderTaskKind::Alpha(..) |
RenderTaskKind::CachePrimitive(..) |
RenderTaskKind::Picture(..) |
RenderTaskKind::VerticalBlur(..) |
RenderTaskKind::Readback(..) |
RenderTaskKind::HorizontalBlur(..) => RenderTargetKind::Color,
@ -604,7 +607,7 @@ impl RenderTask {
pub fn is_shared(&self) -> bool {
match self.kind {
RenderTaskKind::Alpha(..) |
RenderTaskKind::CachePrimitive(..) |
RenderTaskKind::Picture(..) |
RenderTaskKind::VerticalBlur(..) |
RenderTaskKind::Readback(..) |
RenderTaskKind::HorizontalBlur(..) => false,

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