зеркало из https://github.com/mozilla/gecko-dev.git
merge autoland to mozilla-central. r=merge a=merge
MozReview-Commit-ID: CdkzY7WJ58G
This commit is contained in:
Коммит
7b58b734df
|
@ -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,
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче