зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-i to m-c, a=merge
This commit is contained in:
Коммит
a6d7a8a0ce
|
@ -57,7 +57,29 @@
|
|||
<menuitem id="context-openlinkintab"
|
||||
label="&openLinkCmdInTab.label;"
|
||||
accesskey="&openLinkCmdInTab.accesskey;"
|
||||
oncommand="gContextMenu.openLinkInTab();"/>
|
||||
usercontextid="0"
|
||||
oncommand="gContextMenu.openLinkInTab(event);"/>
|
||||
|
||||
<menu id="context-openlinkinusercontext-menu"
|
||||
label="&openLinkCmdInContainerTab.label;"
|
||||
accesskey="&openLinkCmdInContainerTab.accesskey;"
|
||||
hidden="true">
|
||||
<menupopup oncommand="gContextMenu.openLinkInTab(event);">
|
||||
<menuitem label="&userContextPersonal.label;"
|
||||
usercontextid="1"
|
||||
accesskey="&userContextPersonal.accesskey;"/>
|
||||
<menuitem label="&userContextWork.label;"
|
||||
usercontextid="2"
|
||||
accesskey="&userContextWork.accesskey;"/>
|
||||
<menuitem label="&userContextBanking.label;"
|
||||
usercontextid="3"
|
||||
accesskey="&userContextBanking.accesskey;"/>
|
||||
<menuitem label="&userContextShopping.label;"
|
||||
usercontextid="4"
|
||||
accesskey="&userContextShopping.accesskey;"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
|
||||
<menuitem id="context-openlink"
|
||||
label="&openLinkCmd.label;"
|
||||
accesskey="&openLinkCmd.accesskey;"
|
||||
|
|
|
@ -8,9 +8,14 @@
|
|||
var gSafeBrowsing = {
|
||||
|
||||
setReportPhishingMenu: function() {
|
||||
// A phishing page will have a specific about:blocked content documentURI
|
||||
var uri = gBrowser.currentURI;
|
||||
var isPhishingPage = uri && uri.spec.startsWith("about:blocked?e=phishingBlocked");
|
||||
// In order to detect whether or not we're at the phishing warning
|
||||
// page, we have to check the documentURI instead of the currentURI.
|
||||
// This is because when the DocShell loads an error page, the
|
||||
// currentURI stays at the original target, while the documentURI
|
||||
// will point to the internal error page we loaded instead.
|
||||
var docURI = gBrowser.selectedBrowser.documentURI;
|
||||
var isPhishingPage =
|
||||
docURI && docURI.spec.startsWith("about:blocked?e=phishingBlocked");
|
||||
|
||||
// Show/hide the appropriate menu item.
|
||||
document.getElementById("menu_HelpPopup_reportPhishingtoolmenu")
|
||||
|
@ -26,6 +31,9 @@ var gSafeBrowsing = {
|
|||
if (!broadcaster)
|
||||
return;
|
||||
|
||||
// Now look at the currentURI to learn which page we were trying
|
||||
// to browse to.
|
||||
let uri = gBrowser.currentURI;
|
||||
if (uri && (uri.schemeIs("http") || uri.schemeIs("https")))
|
||||
broadcaster.removeAttribute("disabled");
|
||||
else
|
||||
|
|
|
@ -144,9 +144,11 @@ nsContextMenu.prototype = {
|
|||
|
||||
var shouldShow = this.onSaveableLink || isMailtoInternal || this.onPlainTextLink;
|
||||
var isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(window);
|
||||
var showContainers = Services.prefs.getBoolPref("privacy.userContext.enabled");
|
||||
this.showItem("context-openlink", shouldShow && !isWindowPrivate);
|
||||
this.showItem("context-openlinkprivate", shouldShow);
|
||||
this.showItem("context-openlinkintab", shouldShow);
|
||||
this.showItem("context-openlinkinusercontext-menu", shouldShow && showContainers);
|
||||
this.showItem("context-openlinkincurrent", this.onPlainTextLink);
|
||||
this.showItem("context-sep-open", shouldShow);
|
||||
},
|
||||
|
@ -960,7 +962,7 @@ nsContextMenu.prototype = {
|
|||
},
|
||||
|
||||
// Open linked-to URL in a new tab.
|
||||
openLinkInTab: function() {
|
||||
openLinkInTab: function(event) {
|
||||
urlSecurityCheck(this.linkURL, this.principal);
|
||||
let referrerURI = gContextMenuContentData.documentURIObject;
|
||||
|
||||
|
@ -981,6 +983,7 @@ nsContextMenu.prototype = {
|
|||
|
||||
let params = this._openLinkInParameters({
|
||||
allowMixedContent: persistAllowMixedContentInChildTab,
|
||||
userContextId: event.target.getAttribute('usercontextid'),
|
||||
});
|
||||
openLinkIn(this.linkURL, "tab", params);
|
||||
},
|
||||
|
|
|
@ -5,8 +5,6 @@ support-files = head.js
|
|||
[browser_bug400731.js]
|
||||
skip-if = e10s
|
||||
[browser_bug415846.js]
|
||||
skip-if = true
|
||||
# Disabled because it seems to now touch network resources
|
||||
# skip-if = os == "mac"
|
||||
skip-if = os == "mac" || e10s
|
||||
# Disabled on Mac because of its bizarre special-and-unique
|
||||
# snowflake of a help menu.
|
||||
|
|
|
@ -3,60 +3,84 @@ menu items.
|
|||
|
||||
Mac makes this astonishingly painful to test since their help menu is special magic,
|
||||
but we can at least test it on the other platforms.*/
|
||||
var menu;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
const NORMAL_PAGE = "http://example.com";
|
||||
const PHISH_PAGE = "http://www.itisatrap.org/firefox/its-a-trap.html";
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
/**
|
||||
* Opens a new tab and browses to some URL, tests for the existence
|
||||
* of the phishing menu items, and then runs a test function to check
|
||||
* the state of the menu once opened. This function will take care of
|
||||
* opening and closing the menu.
|
||||
*
|
||||
* @param url (string)
|
||||
* The URL to browse the tab to.
|
||||
* @param testFn (function)
|
||||
* The function to run once the menu has been opened. This
|
||||
* function will be passed the "reportMenu" and "errorMenu"
|
||||
* DOM nodes as arguments, in that order. This function
|
||||
* should not yield anything.
|
||||
* @returns Promise
|
||||
*/
|
||||
function check_menu_at_page(url, testFn) {
|
||||
return BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: "about:blank",
|
||||
}, function*(browser) {
|
||||
// We don't get load events when the DocShell redirects to error
|
||||
// pages, but we do get DOMContentLoaded, so we'll wait for that.
|
||||
let dclPromise = ContentTask.spawn(browser, null, function*() {
|
||||
yield ContentTaskUtils.waitForEvent(this, "DOMContentLoaded", false);
|
||||
});
|
||||
browser.loadURI(url);
|
||||
yield dclPromise;
|
||||
|
||||
// Navigate to a normal site
|
||||
gBrowser.addEventListener("DOMContentLoaded", testNormal, false);
|
||||
content.location = "http://example.com/";
|
||||
let menu = document.getElementById("menu_HelpPopup");
|
||||
ok(menu, "Help menu should exist");
|
||||
|
||||
let reportMenu =
|
||||
document.getElementById("menu_HelpPopup_reportPhishingtoolmenu");
|
||||
ok(reportMenu, "Report phishing menu item should exist");
|
||||
|
||||
let errorMenu =
|
||||
document.getElementById("menu_HelpPopup_reportPhishingErrortoolmenu");
|
||||
ok(errorMenu, "Report phishing error menu item should exist");
|
||||
|
||||
let menuOpen = BrowserTestUtils.waitForEvent(menu, "popupshown");
|
||||
menu.openPopup(null, "", 0, 0, false, null);
|
||||
yield menuOpen;
|
||||
|
||||
testFn(reportMenu, errorMenu);
|
||||
|
||||
let menuClose = BrowserTestUtils.waitForEvent(menu, "popuphidden");
|
||||
menu.hidePopup();
|
||||
yield menuClose;
|
||||
});
|
||||
}
|
||||
|
||||
function testNormal() {
|
||||
gBrowser.removeEventListener("DOMContentLoaded", testNormal, false);
|
||||
/**
|
||||
* Tests that we show the "Report this page" menu item at a normal
|
||||
* page.
|
||||
*/
|
||||
add_task(function*() {
|
||||
yield check_menu_at_page(NORMAL_PAGE, (reportMenu, errorMenu) => {
|
||||
ok(!reportMenu.hidden,
|
||||
"Report phishing menu should be visible on normal sites");
|
||||
ok(errorMenu.hidden,
|
||||
"Report error menu item should be hidden on normal sites");
|
||||
});
|
||||
});
|
||||
|
||||
// open the menu, to force it to update
|
||||
menu = document.getElementById("menu_HelpPopup");
|
||||
ok(menu, "Help menu should exist!");
|
||||
/**
|
||||
* Tests that we show the "Report this page is okay" menu item at
|
||||
* a reported attack site.
|
||||
*/
|
||||
add_task(function*() {
|
||||
yield check_menu_at_page(PHISH_PAGE, (reportMenu, errorMenu) => {
|
||||
ok(reportMenu.hidden,
|
||||
"Report phishing menu should be hidden on phishing sites");
|
||||
ok(!errorMenu.hidden,
|
||||
"Report error menu item should be visible on phishing sites");
|
||||
});
|
||||
});
|
||||
|
||||
menu.addEventListener("popupshown", testNormal_PopupListener, false);
|
||||
menu.openPopup(null, "", 0, 0, false, null);
|
||||
}
|
||||
|
||||
function testNormal_PopupListener() {
|
||||
menu.removeEventListener("popupshown", testNormal_PopupListener, false);
|
||||
|
||||
var reportMenu = document.getElementById("menu_HelpPopup_reportPhishingtoolmenu");
|
||||
var errorMenu = document.getElementById("menu_HelpPopup_reportPhishingErrortoolmenu");
|
||||
is(reportMenu.hidden, false, "Report phishing menu should be visible on normal sites");
|
||||
is(errorMenu.hidden, true, "Report error menu item should be hidden on normal sites");
|
||||
menu.hidePopup();
|
||||
|
||||
// Now launch the phishing test. Can't use onload here because error pages don't
|
||||
// fire normal load events.
|
||||
window.addEventListener("DOMContentLoaded", testPhishing, true);
|
||||
content.location = "http://www.itisatrap.org/firefox/its-a-trap.html";
|
||||
}
|
||||
|
||||
function testPhishing() {
|
||||
window.removeEventListener("DOMContentLoaded", testPhishing, true);
|
||||
|
||||
menu.addEventListener("popupshown", testPhishing_PopupListener, false);
|
||||
menu.openPopup(null, "", 0, 0, false, null);
|
||||
}
|
||||
|
||||
function testPhishing_PopupListener() {
|
||||
menu.removeEventListener("popupshown", testPhishing_PopupListener, false);
|
||||
|
||||
var reportMenu = document.getElementById("menu_HelpPopup_reportPhishingtoolmenu");
|
||||
var errorMenu = document.getElementById("menu_HelpPopup_reportPhishingErrortoolmenu");
|
||||
is(reportMenu.hidden, true, "Report phishing menu should be hidden on phishing sites");
|
||||
is(errorMenu.hidden, false, "Report error menu item should be visible on phishing sites");
|
||||
menu.hidePopup();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
|
|
|
@ -529,6 +529,8 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
|||
<!ENTITY openFrameCmdInTab.accesskey "T">
|
||||
<!ENTITY openFrameCmd.label "Open Frame in New Window">
|
||||
<!ENTITY openFrameCmd.accesskey "W">
|
||||
<!ENTITY openLinkCmdInContainerTab.label "Open Link in New Container Tab">
|
||||
<!ENTITY openLinkCmdInContainerTab.accesskey "C">
|
||||
<!ENTITY showOnlyThisFrameCmd.label "Show Only This Frame">
|
||||
<!ENTITY showOnlyThisFrameCmd.accesskey "S">
|
||||
<!ENTITY reloadCmd.commandkey "r">
|
||||
|
|
|
@ -3492,22 +3492,19 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
|
|||
|
||||
nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem);
|
||||
nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem);
|
||||
if (!!targetDS != !!accessingDS) {
|
||||
// We must be able to convert both or neither to nsIDocShell.
|
||||
if (!targetDS || !accessingDS) {
|
||||
// We must be able to convert both to nsIDocShell.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (targetDS && accessingDS &&
|
||||
(targetDS->GetIsInBrowserElement() !=
|
||||
accessingDS->GetIsInBrowserElement() ||
|
||||
targetDS->GetAppId() != accessingDS->GetAppId())) {
|
||||
if (targetDS->GetIsInBrowserElement() != accessingDS->GetIsInBrowserElement() ||
|
||||
targetDS->GetAppId() != accessingDS->GetAppId()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// A private document can't access a non-private one, and vice versa.
|
||||
if (aTargetItem->GetDocument()->GetLoadContext()->UsePrivateBrowsing() !=
|
||||
aAccessingItem->GetDocument()->GetLoadContext()->UsePrivateBrowsing())
|
||||
{
|
||||
if (static_cast<nsDocShell*>(targetDS.get())->UsePrivateBrowsing() !=
|
||||
static_cast<nsDocShell*>(accessingDS.get())->UsePrivateBrowsing()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
document.write("<h5 id='dynamic'>document.written content</h5>");
|
||||
document.close();
|
||||
window.history.go(-1);
|
||||
opener.setTimeout("isTestDynamic()", 2500);
|
||||
}
|
||||
|
||||
function start() {
|
||||
|
@ -14,6 +13,15 @@
|
|||
setTimeout(run, 0);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("pageshow",
|
||||
function() {
|
||||
++opener.file_document_write_1_loadCount;
|
||||
if (opener.file_document_write_1_loadCount == 2) {
|
||||
opener.setTimeout("isTestDynamic()", 0);
|
||||
}
|
||||
opener.ok(opener.file_document_write_1_loadCount <= 2);
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body onload="start();">
|
||||
|
|
|
@ -49,6 +49,7 @@ function nextTest_() {
|
|||
}
|
||||
|
||||
// Needed by file_document_write_1.html
|
||||
window.file_document_write_1_loadCount = 0;
|
||||
function isTestDynamic() {
|
||||
var dyn = testWindow.document.getElementById("dynamic");
|
||||
is(dyn, null, "Should have gone back to the static page!");
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "nsIAtom.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ComputedTimingFunction.h" // ComputedTimingFunction
|
||||
#include "mozilla/dom/Element.h" // For dom::Element
|
||||
|
||||
|
@ -69,7 +70,7 @@ AnimationUtils::ParseEasing(const dom::Element* aTarget,
|
|||
NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR) {
|
||||
return Nothing();
|
||||
}
|
||||
// Fall through
|
||||
MOZ_FALLTHROUGH;
|
||||
case eCSSUnit_Cubic_Bezier:
|
||||
case eCSSUnit_Steps: {
|
||||
nsTimingFunction timingFunction;
|
||||
|
|
|
@ -1004,7 +1004,8 @@ ParentRunnable::Run()
|
|||
|
||||
// Metadata is now open.
|
||||
if (!SendOnOpenMetadataForRead(mMetadata)) {
|
||||
Unused << Send__delete__(this, JS::AsmJSCache_InternalError);
|
||||
Fail();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1038,7 +1039,8 @@ ParentRunnable::Run()
|
|||
FileDescriptor::PlatformHandleType handle =
|
||||
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFileDesc));
|
||||
if (!SendOnOpenCacheFile(mFileSize, FileDescriptor(handle))) {
|
||||
Unused << Send__delete__(this, JS::AsmJSCache_InternalError);
|
||||
Fail();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -1547,7 +1547,7 @@ bool
|
|||
Console::ProcessArguments(JSContext* aCx,
|
||||
const Sequence<JS::Value>& aData,
|
||||
Sequence<JS::Value>& aSequence,
|
||||
Sequence<JS::Value>& aStyles) const
|
||||
Sequence<nsString>& aStyles) const
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
|
@ -1693,13 +1693,18 @@ Console::ProcessArguments(JSContext* aCx,
|
|||
int32_t diff = aSequence.Length() - aStyles.Length();
|
||||
if (diff > 0) {
|
||||
for (int32_t i = 0; i < diff; i++) {
|
||||
if (!aStyles.AppendElement(JS::NullValue(), fallible)) {
|
||||
if (!aStyles.AppendElement(NullString(), fallible)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!aStyles.AppendElement(JS::StringValue(jsString), fallible)) {
|
||||
nsAutoJSString string;
|
||||
if (!string.init(aCx, jsString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aStyles.AppendElement(string, fallible)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@ private:
|
|||
bool
|
||||
ProcessArguments(JSContext* aCx, const Sequence<JS::Value>& aData,
|
||||
Sequence<JS::Value>& aSequence,
|
||||
Sequence<JS::Value>& aStyles) const;
|
||||
Sequence<nsString>& aStyles) const;
|
||||
|
||||
void
|
||||
MakeFormatString(nsCString& aFormat, int32_t aInteger, int32_t aMantissa,
|
||||
|
|
|
@ -151,6 +151,34 @@ GetNextRangeCommonAncestor(nsINode* aNode)
|
|||
return aNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Comparator suitable for mozilla::BinarySearchIf for searching a collection
|
||||
* of nsRange* for an overlap of (mNode, mStartOffset) .. (mNode, mEndOffset).
|
||||
*/
|
||||
struct IsItemInRangeComparator
|
||||
{
|
||||
nsINode* mNode;
|
||||
uint32_t mStartOffset;
|
||||
uint32_t mEndOffset;
|
||||
|
||||
int operator()(const nsRange* const aRange) const
|
||||
{
|
||||
int32_t cmp = nsContentUtils::ComparePoints(mNode, mEndOffset,
|
||||
aRange->GetStartParent(),
|
||||
aRange->StartOffset());
|
||||
if (cmp == 1) {
|
||||
cmp = nsContentUtils::ComparePoints(mNode, mStartOffset,
|
||||
aRange->GetEndParent(),
|
||||
aRange->EndOffset());
|
||||
if (cmp == -1) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ bool
|
||||
nsRange::IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
|
||||
uint32_t aEndOffset)
|
||||
|
@ -160,24 +188,45 @@ nsRange::IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
|
|||
nsINode* n = GetNextRangeCommonAncestor(aNode);
|
||||
NS_ASSERTION(n || !aNode->IsSelectionDescendant(),
|
||||
"orphan selection descendant");
|
||||
|
||||
// Collect the potential ranges and their selection objects.
|
||||
RangeHashTable ancestorSelectionRanges;
|
||||
nsTHashtable<nsPtrHashKey<Selection>> ancestorSelections;
|
||||
uint32_t maxRangeCount = 0;
|
||||
for (; n; n = GetNextRangeCommonAncestor(n->GetParentNode())) {
|
||||
RangeHashTable* ranges =
|
||||
static_cast<RangeHashTable*>(n->GetProperty(nsGkAtoms::range));
|
||||
for (auto iter = ranges->ConstIter(); !iter.Done(); iter.Next()) {
|
||||
nsRange* range = iter.Get()->GetKey();
|
||||
if (range->IsInSelection() && !range->Collapsed()) {
|
||||
int32_t cmp = nsContentUtils::ComparePoints(aNode, aEndOffset,
|
||||
range->GetStartParent(),
|
||||
range->StartOffset());
|
||||
if (cmp == 1) {
|
||||
cmp = nsContentUtils::ComparePoints(aNode, aStartOffset,
|
||||
range->GetEndParent(),
|
||||
range->EndOffset());
|
||||
if (cmp == -1) {
|
||||
return true;
|
||||
}
|
||||
ancestorSelectionRanges.PutEntry(range);
|
||||
Selection* selection = range->mSelection;
|
||||
ancestorSelections.PutEntry(selection);
|
||||
maxRangeCount = std::max(maxRangeCount, selection->RangeCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ancestorSelectionRanges.IsEmpty()) {
|
||||
nsTArray<const nsRange*> sortedRanges(maxRangeCount);
|
||||
for (auto iter = ancestorSelections.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
Selection* selection = iter.Get()->GetKey();
|
||||
// Sort the found ranges for |selection| in document order
|
||||
// (Selection::GetRangeAt returns its ranges ordered).
|
||||
for (uint32_t i = 0, len = selection->RangeCount(); i < len; ++i) {
|
||||
nsRange* range = selection->GetRangeAt(i);
|
||||
if (ancestorSelectionRanges.Contains(range)) {
|
||||
sortedRanges.AppendElement(range);
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(!sortedRanges.IsEmpty());
|
||||
// Binary search the now sorted ranges.
|
||||
IsItemInRangeComparator comparator = { aNode, aStartOffset, aEndOffset };
|
||||
size_t unused;
|
||||
if (mozilla::BinarySearchIf(sortedRanges, 0, sortedRanges.Length(), comparator, &unused)) {
|
||||
return true;
|
||||
}
|
||||
sortedRanges.ClearAndRetainStorage();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -3105,6 +3154,12 @@ nsRange::Constructor(const GlobalObject& aGlobal,
|
|||
return window->GetDoc()->CreateRange(aRv);
|
||||
}
|
||||
|
||||
static bool ExcludeIfNextToNonSelectable(nsIContent* aContent)
|
||||
{
|
||||
return aContent->IsNodeOfType(nsINode::eTEXT) &&
|
||||
aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE);
|
||||
}
|
||||
|
||||
void
|
||||
nsRange::ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges)
|
||||
{
|
||||
|
@ -3123,6 +3178,10 @@ nsRange::ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges)
|
|||
|
||||
bool added = false;
|
||||
bool seenSelectable = false;
|
||||
// |firstNonSelectableContent| is the first node in a consecutive sequence
|
||||
// of non-IsSelectable nodes. When we find a selectable node after such
|
||||
// a sequence we'll end the last nsRange, create a new one and restart
|
||||
// the outer loop.
|
||||
nsIContent* firstNonSelectableContent = nullptr;
|
||||
while (true) {
|
||||
ErrorResult err;
|
||||
|
@ -3132,12 +3191,19 @@ nsRange::ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges)
|
|||
nsIContent* content =
|
||||
node && node->IsContent() ? node->AsContent() : nullptr;
|
||||
if (content) {
|
||||
nsIFrame* frame = content->GetPrimaryFrame();
|
||||
for (nsIContent* p = content; !frame && (p = p->GetParent()); ) {
|
||||
frame = p->GetPrimaryFrame();
|
||||
if (firstNonSelectableContent && ExcludeIfNextToNonSelectable(content)) {
|
||||
// Ignorable whitespace next to a sequence of non-selectable nodes
|
||||
// counts as non-selectable (bug 1216001).
|
||||
selectable = false;
|
||||
}
|
||||
if (frame) {
|
||||
frame->IsSelectable(&selectable, nullptr);
|
||||
if (selectable) {
|
||||
nsIFrame* frame = content->GetPrimaryFrame();
|
||||
for (nsIContent* p = content; !frame && (p = p->GetParent()); ) {
|
||||
frame = p->GetPrimaryFrame();
|
||||
}
|
||||
if (frame) {
|
||||
frame->IsSelectable(&selectable, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -252,6 +252,14 @@ public:
|
|||
bool *outNodeBefore,
|
||||
bool *outNodeAfter);
|
||||
|
||||
/**
|
||||
* Return true if any part of (aNode, aStartOffset) .. (aNode, aEndOffset)
|
||||
* overlaps any nsRange in aNode's GetNextRangeCommonAncestor ranges (i.e.
|
||||
* where aNode is a descendant of a range's common ancestor node).
|
||||
* If a nsRange starts in (aNode, aEndOffset) or if it ends in
|
||||
* (aNode, aStartOffset) then it is non-overlapping and the result is false
|
||||
* for that nsRange. Collapsed ranges always counts as non-overlapping.
|
||||
*/
|
||||
static bool IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
|
||||
uint32_t aEndOffset);
|
||||
|
||||
|
@ -298,6 +306,14 @@ protected:
|
|||
*/
|
||||
nsINode* GetRegisteredCommonAncestor();
|
||||
|
||||
// Helper to IsNodeSelected.
|
||||
static bool IsNodeInSortedRanges(nsINode* aNode,
|
||||
uint32_t aStartOffset,
|
||||
uint32_t aEndOffset,
|
||||
const nsTArray<const nsRange*>& aRanges,
|
||||
size_t aRangeStart,
|
||||
size_t aRangeEnd);
|
||||
|
||||
struct MOZ_STACK_CLASS AutoInvalidateSelection
|
||||
{
|
||||
explicit AutoInvalidateSelection(nsRange* aRange) : mRange(aRange)
|
||||
|
|
|
@ -133,9 +133,15 @@ nsScreen::GetRect(nsRect& aRect)
|
|||
}
|
||||
|
||||
context->GetRect(aRect);
|
||||
LayoutDevicePoint screenTopLeftDev =
|
||||
LayoutDevicePixel::FromAppUnits(aRect.TopLeft(),
|
||||
context->AppUnitsPerDevPixel());
|
||||
DesktopPoint screenTopLeftDesk =
|
||||
screenTopLeftDev / context->GetDesktopToDeviceScale();
|
||||
|
||||
aRect.x = NSToIntRound(screenTopLeftDesk.x);
|
||||
aRect.y = NSToIntRound(screenTopLeftDesk.y);
|
||||
|
||||
aRect.x = nsPresContext::AppUnitsToIntCSSPixels(aRect.x);
|
||||
aRect.y = nsPresContext::AppUnitsToIntCSSPixels(aRect.y);
|
||||
aRect.height = nsPresContext::AppUnitsToIntCSSPixels(aRect.height);
|
||||
aRect.width = nsPresContext::AppUnitsToIntCSSPixels(aRect.width);
|
||||
|
||||
|
@ -156,10 +162,21 @@ nsScreen::GetAvailRect(nsRect& aRect)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRect r;
|
||||
context->GetRect(r);
|
||||
LayoutDevicePoint screenTopLeftDev =
|
||||
LayoutDevicePixel::FromAppUnits(r.TopLeft(),
|
||||
context->AppUnitsPerDevPixel());
|
||||
DesktopPoint screenTopLeftDesk =
|
||||
screenTopLeftDev / context->GetDesktopToDeviceScale();
|
||||
|
||||
context->GetClientRect(aRect);
|
||||
|
||||
aRect.x = nsPresContext::AppUnitsToIntCSSPixels(aRect.x);
|
||||
aRect.y = nsPresContext::AppUnitsToIntCSSPixels(aRect.y);
|
||||
aRect.x = NSToIntRound(screenTopLeftDesk.x) +
|
||||
nsPresContext::AppUnitsToIntCSSPixels(aRect.x - r.x);
|
||||
aRect.y = NSToIntRound(screenTopLeftDesk.y) +
|
||||
nsPresContext::AppUnitsToIntCSSPixels(aRect.y - r.y);
|
||||
|
||||
aRect.height = nsPresContext::AppUnitsToIntCSSPixels(aRect.height);
|
||||
aRect.width = nsPresContext::AppUnitsToIntCSSPixels(aRect.width);
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
src: url("Ahem.ttf");
|
||||
}
|
||||
body { font-family: Ahem; font-size: 20px; }
|
||||
s { -moz-user-select: none; }
|
||||
s, .non-selectable { -moz-user-select: none; }
|
||||
n { display: none; }
|
||||
a { position:absolute; bottom: 0; right:0; }
|
||||
.text { -moz-user-select: text; }
|
||||
|
@ -34,6 +34,16 @@ a { position:absolute; bottom: 0; right:0; }
|
|||
<div id="testB"><n><s>aaaa</s>aaa</n>bbbbbbbbccccccc</div>
|
||||
<div id="testC">aaaaaaabbbbbbbb<n>cc<s>c</s>cccc</n></div>
|
||||
<div id="testE">aaa<s id="testEc1">aaaa<a class="text">bbbb</a>dd<a>cccc</a>ddddddd</s>eeee</div>
|
||||
<div id="testF">aaaa
|
||||
<div class="non-selectable">x</div>
|
||||
<div class="non-selectable">x</div>
|
||||
<div class="non-selectable">x</div>
|
||||
bbbb</div>
|
||||
<div id="testG" style="white-space:pre">aaaa
|
||||
<div class="non-selectable">x</div>
|
||||
<div class="non-selectable">x</div>
|
||||
<div class="non-selectable">x</div>
|
||||
bbbb</div>
|
||||
|
||||
<iframe id="testD" src="data:text/html,<body>aaaa<span style='-moz-user-select:none'>bbbb</span>cccc"></iframe>
|
||||
|
||||
|
@ -100,9 +110,11 @@ function test()
|
|||
is(NL(r.toString()), text, e.id + ": range["+index+"].toString()")
|
||||
}
|
||||
|
||||
function node(e, index)
|
||||
function node(e, arg)
|
||||
{
|
||||
return index == -1 ? e : e.childNodes[index];
|
||||
if (typeof arg == "number")
|
||||
return arg == -1 ? e : e.childNodes[arg];
|
||||
return arg;
|
||||
}
|
||||
|
||||
function checkRangeCount(n, e)
|
||||
|
@ -258,6 +270,22 @@ function test()
|
|||
checkRanges([[0,1,-1,1]], e);
|
||||
doneTest(e);
|
||||
|
||||
clear();
|
||||
e = document.getElementById('testF');
|
||||
synthesizeMouse(e, 1, 1, {});
|
||||
synthesizeMouse(e, 400, 100, { shiftKey: true });
|
||||
checkText("aaaa bbbb", e);
|
||||
checkRanges([[0,0,-1,1],[6,0,6,5]], e);
|
||||
doneTest(e);
|
||||
|
||||
clear();
|
||||
e = document.getElementById('testG');
|
||||
synthesizeMouse(e, 1, 1, {});
|
||||
synthesizeMouse(e, 400, 180, { shiftKey: true });
|
||||
checkText("aaaa bbbb", e); // XXX this doesn't seem right - bug 1247799
|
||||
checkRanges([[0,0,-1,1],[2,0,-1,3],[4,0,-1,5],[6,0,6,5]], e);
|
||||
doneTest(e);
|
||||
|
||||
// ======================================================
|
||||
// ==================== Script tests ====================
|
||||
// ======================================================
|
||||
|
|
|
@ -31,8 +31,9 @@ ENUM_ENTRY_VARIABLE_NAME = 'strings'
|
|||
INSTANCE_RESERVED_SLOTS = 1
|
||||
|
||||
|
||||
def memberReservedSlot(member):
|
||||
return "(DOM_INSTANCE_RESERVED_SLOTS + %d)" % member.slotIndex
|
||||
def memberReservedSlot(member, descriptor):
|
||||
return ("(DOM_INSTANCE_RESERVED_SLOTS + %d)" %
|
||||
member.slotIndices[descriptor.interface.identifier.name])
|
||||
|
||||
|
||||
def toStringBool(arg):
|
||||
|
@ -2149,7 +2150,7 @@ def clearableCachedAttrs(descriptor):
|
|||
m.isAttr() and
|
||||
# Constants should never need clearing!
|
||||
m.dependsOn != "Nothing" and
|
||||
m.slotIndex is not None)
|
||||
m.slotIndices is not None)
|
||||
|
||||
|
||||
def MakeClearCachedValueNativeName(member):
|
||||
|
@ -3805,8 +3806,6 @@ class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod):
|
|||
}
|
||||
// Getter handled setting our reserved slots
|
||||
""",
|
||||
slot=memberReservedSlot(m),
|
||||
interface=self.descriptor.interface.identifier.name,
|
||||
member=m.identifier.name)
|
||||
|
||||
body += "\nreturn true;\n"
|
||||
|
@ -3828,7 +3827,7 @@ class CGClearCachedValueMethod(CGAbstractMethod):
|
|||
CGAbstractMethod.__init__(self, descriptor, name, returnType, args)
|
||||
|
||||
def definition_body(self):
|
||||
slotIndex = memberReservedSlot(self.member)
|
||||
slotIndex = memberReservedSlot(self.member, self.descriptor)
|
||||
if self.member.getExtendedAttribute("StoreInSlot"):
|
||||
# We have to root things and save the old value in case
|
||||
# regetting fails, so we can restore it.
|
||||
|
@ -7371,7 +7370,7 @@ class CGPerSignatureCall(CGThing):
|
|||
"NewObject implies that we need to keep the object alive with a strong reference.");
|
||||
""")
|
||||
|
||||
setSlot = self.idlNode.isAttr() and self.idlNode.slotIndex is not None
|
||||
setSlot = self.idlNode.isAttr() and self.idlNode.slotIndices is not None
|
||||
if setSlot:
|
||||
# For attributes in slots, we want to do some
|
||||
# post-processing once we've wrapped them.
|
||||
|
@ -7418,7 +7417,7 @@ class CGPerSignatureCall(CGThing):
|
|||
"args.rval().isObject()")
|
||||
postSteps += freezeValue.define()
|
||||
postSteps += ("js::SetReservedSlot(reflector, %s, args.rval());\n" %
|
||||
memberReservedSlot(self.idlNode))
|
||||
memberReservedSlot(self.idlNode, self.descriptor))
|
||||
# For the case of Cached attributes, go ahead and preserve our
|
||||
# wrapper if needed. We need to do this because otherwise the
|
||||
# wrapper could get garbage-collected and the cached value would
|
||||
|
@ -8003,7 +8002,7 @@ class CGSetterCall(CGPerSignatureCall):
|
|||
|
||||
def wrap_return_value(self):
|
||||
attr = self.idlNode
|
||||
if self.descriptor.wrapperCache and attr.slotIndex is not None:
|
||||
if self.descriptor.wrapperCache and attr.slotIndices is not None:
|
||||
if attr.getExtendedAttribute("StoreInSlot"):
|
||||
args = "cx, self"
|
||||
else:
|
||||
|
@ -8550,7 +8549,7 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
|||
return getMaplikeOrSetlikeSizeGetterBody(self.descriptor, self.attr)
|
||||
nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
|
||||
self.attr)
|
||||
if self.attr.slotIndex is not None:
|
||||
if self.attr.slotIndices is not None:
|
||||
if self.descriptor.hasXPConnectImpls:
|
||||
raise TypeError("Interface '%s' has XPConnect impls, so we "
|
||||
"can't use our slot for property '%s'!" %
|
||||
|
@ -8576,7 +8575,7 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
|||
}
|
||||
|
||||
""",
|
||||
slot=memberReservedSlot(self.attr),
|
||||
slot=memberReservedSlot(self.attr, self.descriptor),
|
||||
maybeWrap=getMaybeWrapValueFuncForType(self.attr.type))
|
||||
else:
|
||||
prefix = ""
|
||||
|
@ -8827,10 +8826,13 @@ class CGMemberJITInfo(CGThing):
|
|||
slotIndex=slotIndex)
|
||||
return initializer.rstrip()
|
||||
|
||||
slotAssert = dedent(
|
||||
slotAssert = fill(
|
||||
"""
|
||||
static_assert(%s <= JSJitInfo::maxSlotIndex, "We won't fit");
|
||||
""" % slotIndex)
|
||||
static_assert(${slotIndex} <= JSJitInfo::maxSlotIndex, "We won't fit");
|
||||
static_assert(${slotIndex} < ${classReservedSlots}, "There is no slot for us");
|
||||
""",
|
||||
slotIndex=slotIndex,
|
||||
classReservedSlots=INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots)
|
||||
if args is not None:
|
||||
argTypes = "%s_argTypes" % infoName
|
||||
args = [CGMemberJITInfo.getJSArgType(arg.type) for arg in args]
|
||||
|
@ -8878,10 +8880,10 @@ class CGMemberJITInfo(CGThing):
|
|||
|
||||
getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
|
||||
isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
|
||||
if self.member.slotIndex is not None:
|
||||
if self.member.slotIndices is not None:
|
||||
assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached")
|
||||
isLazilyCachedInSlot = not isAlwaysInSlot
|
||||
slotIndex = memberReservedSlot(self.member)
|
||||
slotIndex = memberReservedSlot(self.member, self.descriptor)
|
||||
# We'll statically assert that this is not too big in
|
||||
# CGUpdateMemberSlotsMethod, in the case when
|
||||
# isAlwaysInSlot is true.
|
||||
|
@ -15328,7 +15330,7 @@ def getMaplikeOrSetlikeBackingObject(descriptor, maplikeOrSetlike, helperImpl=No
|
|||
PreserveWrapper<${selfType}>(self);
|
||||
}
|
||||
""",
|
||||
slot=memberReservedSlot(maplikeOrSetlike),
|
||||
slot=memberReservedSlot(maplikeOrSetlike, descriptor),
|
||||
func_prefix=func_prefix,
|
||||
errorReturn=getMaplikeOrSetlikeErrorReturn(helperImpl),
|
||||
selfType=descriptor.nativeType)
|
||||
|
|
|
@ -978,7 +978,9 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
|||
(member.getExtendedAttribute("StoreInSlot") or
|
||||
member.getExtendedAttribute("Cached"))) or
|
||||
member.isMaplikeOrSetlike()):
|
||||
member.slotIndex = self.totalMembersInSlots
|
||||
if member.slotIndices is None:
|
||||
member.slotIndices = dict()
|
||||
member.slotIndices[self.identifier.name] = self.totalMembersInSlots
|
||||
self.totalMembersInSlots += 1
|
||||
if member.getExtendedAttribute("StoreInSlot"):
|
||||
self._ownMembersInSlots += 1
|
||||
|
@ -3599,7 +3601,7 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
|
|||
IDLMaplikeOrSetlikeOrIterableBase.__init__(self, location, identifier, maplikeOrSetlikeType,
|
||||
keyType, valueType, IDLInterfaceMember.Tags.MaplikeOrSetlike)
|
||||
self.readonly = readonly
|
||||
self.slotIndex = None
|
||||
self.slotIndices = None
|
||||
|
||||
# When generating JSAPI access code, we need to know the backing object
|
||||
# type prefix to create the correct function. Generate here for reuse.
|
||||
|
@ -3793,7 +3795,7 @@ class IDLAttribute(IDLInterfaceMember):
|
|||
self.stringifier = stringifier
|
||||
self.enforceRange = False
|
||||
self.clamp = False
|
||||
self.slotIndex = None
|
||||
self.slotIndices = None
|
||||
assert maplikeOrSetlike is None or isinstance(maplikeOrSetlike, IDLMaplikeOrSetlike)
|
||||
self.maplikeOrSetlike = maplikeOrSetlike
|
||||
self.dependsOn = "Everything"
|
||||
|
|
|
@ -1570,9 +1570,7 @@ CanvasRenderingContext2D::ReturnTarget()
|
|||
{
|
||||
if (mTarget && mBufferProvider) {
|
||||
CurrentState().transform = mTarget->GetTransform();
|
||||
DrawTarget* oldDT = mTarget;
|
||||
mTarget = nullptr;
|
||||
mBufferProvider->ReturnAndUseDT(oldDT);
|
||||
mBufferProvider->ReturnAndUseDT(mTarget.forget());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4916,6 +4914,9 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& aWindow, double aX,
|
|||
|
||||
nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
|
||||
Unused << shell->RenderDocument(r, renderDocFlags, backgroundColor, thebes);
|
||||
// If this canvas was contained in the drawn window, the pre-transaction callback
|
||||
// may have returned its DT. If so, we must reacquire it here.
|
||||
EnsureTarget();
|
||||
if (drawDT) {
|
||||
RefPtr<SourceSurface> snapshot = drawDT->Snapshot();
|
||||
RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
|
||||
|
|
|
@ -20,28 +20,33 @@ GetFBInfoForBlit(const WebGLFramebuffer* fb, const char* const fbInfo,
|
|||
const webgl::FormatInfo** const out_depthFormat,
|
||||
const webgl::FormatInfo** const out_stencilFormat)
|
||||
{
|
||||
*out_samples = 1; // TODO
|
||||
*out_samples = 0;
|
||||
*out_colorFormat = nullptr;
|
||||
*out_depthFormat = nullptr;
|
||||
*out_stencilFormat = nullptr;
|
||||
|
||||
if (fb->ColorAttachment(0).IsDefined()) {
|
||||
const auto& attachment = fb->ColorAttachment(0);
|
||||
*out_samples = attachment.Samples();
|
||||
*out_colorFormat = attachment.Format()->format;
|
||||
}
|
||||
|
||||
if (fb->DepthStencilAttachment().IsDefined()) {
|
||||
const auto& attachment = fb->DepthStencilAttachment();
|
||||
*out_samples = attachment.Samples();
|
||||
|
||||
*out_depthFormat = attachment.Format()->format;
|
||||
*out_stencilFormat = *out_depthFormat;
|
||||
} else {
|
||||
if (fb->DepthAttachment().IsDefined()) {
|
||||
const auto& attachment = fb->DepthAttachment();
|
||||
*out_samples = attachment.Samples();
|
||||
*out_depthFormat = attachment.Format()->format;
|
||||
}
|
||||
|
||||
if (fb->StencilAttachment().IsDefined()) {
|
||||
const auto& attachment = fb->StencilAttachment();
|
||||
*out_samples = attachment.Samples();
|
||||
*out_stencilFormat = attachment.Format()->format;
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +138,7 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
srcSamples = 1; // Always 1.
|
||||
srcSamples = 0; // Always 0.
|
||||
|
||||
GetBackbufferFormats(mOptions, &srcColorFormat, &srcDepthFormat,
|
||||
&srcStencilFormat);
|
||||
|
@ -221,13 +226,13 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
|
|||
return;
|
||||
}
|
||||
|
||||
if (dstSamples != 1) {
|
||||
if (dstSamples != 0) {
|
||||
ErrorInvalidOperation("blitFramebuffer: DRAW_FRAMEBUFFER may not have"
|
||||
" multiple samples.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (srcSamples != 1) {
|
||||
if (srcSamples != 0) {
|
||||
if (mask & LOCAL_GL_COLOR_BUFFER_BIT &&
|
||||
dstColorFormat != srcColorFormat)
|
||||
{
|
||||
|
|
|
@ -15,43 +15,45 @@ void
|
|||
WebGL2Context::GetInternalformatParameter(JSContext* cx, GLenum target,
|
||||
GLenum internalformat, GLenum pname,
|
||||
JS::MutableHandleValue retval,
|
||||
ErrorResult& rv)
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
const char funcName[] = "getInternalfomratParameter";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (target != LOCAL_GL_RENDERBUFFER) {
|
||||
return ErrorInvalidEnumInfo("getInternalfomratParameter: target must be "
|
||||
"RENDERBUFFER. Was:", target);
|
||||
}
|
||||
if (target != LOCAL_GL_RENDERBUFFER) {
|
||||
ErrorInvalidEnum("%s: `target` must be RENDERBUFFER, was: 0x%04x.", funcName,
|
||||
target);
|
||||
return;
|
||||
}
|
||||
|
||||
// GL_INVALID_ENUM is generated if internalformat is not color-,
|
||||
// depth-, or stencil-renderable.
|
||||
// TODO: When format table queries lands.
|
||||
// GL_INVALID_ENUM is generated if internalformat is not color-, depth-, or
|
||||
// stencil-renderable.
|
||||
// TODO: When format table queries lands.
|
||||
|
||||
if (pname != LOCAL_GL_SAMPLES) {
|
||||
return ErrorInvalidEnumInfo("getInternalformatParameter: pname must be SAMPLES. "
|
||||
"Was:", pname);
|
||||
}
|
||||
if (pname != LOCAL_GL_SAMPLES) {
|
||||
ErrorInvalidEnumInfo("%s: `pname` must be SAMPLES, was 0x%04x.", funcName, pname);
|
||||
return;
|
||||
}
|
||||
|
||||
GLint* samples = nullptr;
|
||||
GLint sampleCount = 0;
|
||||
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat,
|
||||
LOCAL_GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
|
||||
if (sampleCount > 0) {
|
||||
samples = new GLint[sampleCount];
|
||||
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat, LOCAL_GL_SAMPLES,
|
||||
sampleCount, samples);
|
||||
}
|
||||
GLint* samples = nullptr;
|
||||
GLint sampleCount = 0;
|
||||
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat,
|
||||
LOCAL_GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
|
||||
if (sampleCount > 0) {
|
||||
samples = new GLint[sampleCount];
|
||||
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat, LOCAL_GL_SAMPLES,
|
||||
sampleCount, samples);
|
||||
}
|
||||
|
||||
JSObject* obj = dom::Int32Array::Create(cx, this, sampleCount, samples);
|
||||
if (!obj) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
JSObject* obj = dom::Int32Array::Create(cx, this, sampleCount, samples);
|
||||
if (!obj) {
|
||||
out_rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
delete[] samples;
|
||||
delete[] samples;
|
||||
|
||||
retval.setObjectOrNull(obj);
|
||||
retval.setObjectOrNull(obj);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -59,14 +61,11 @@ WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples,
|
|||
GLenum internalFormat,
|
||||
GLsizei width, GLsizei height)
|
||||
{
|
||||
const char funcName[] = "renderbufferStorageMultisample";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
const char funcName[] = "renderbufferStorageMultisample";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
//RenderbufferStorage_base(funcName, target, samples, internalFormat, width, height);
|
||||
|
||||
ErrorInvalidOperation("%s: Multisampling is still under development, and is currently"
|
||||
" disabled.", funcName);
|
||||
RenderbufferStorage_base(funcName, target, samples, internalFormat, width, height);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -106,7 +106,6 @@ WebGLContext::WebGLContext()
|
|||
, mMaxFetchedVertices(0)
|
||||
, mMaxFetchedInstances(0)
|
||||
, mBypassShaderValidation(false)
|
||||
, mGLMaxSamples(1)
|
||||
, mNeedsFakeNoAlpha(false)
|
||||
, mNeedsFakeNoDepth(false)
|
||||
, mNeedsFakeNoStencil(false)
|
||||
|
|
|
@ -1114,7 +1114,6 @@ protected:
|
|||
int32_t mGLMaxVertexUniformVectors;
|
||||
uint32_t mGLMaxTransformFeedbackSeparateAttribs;
|
||||
GLuint mGLMaxUniformBufferBindings;
|
||||
GLsizei mGLMaxSamples;
|
||||
|
||||
// What is supported:
|
||||
uint32_t mGLMaxColorAttachments;
|
||||
|
|
|
@ -173,17 +173,13 @@ WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer* wrb)
|
|||
if (wrb && wrb->IsDeleted())
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
// Usually, we would now call into glBindRenderbuffer. However, since we have to
|
||||
// potentially emulate packed-depth-stencil, there's not a specific renderbuffer that
|
||||
// we know we should bind here.
|
||||
// Instead, we do all renderbuffer binding lazily.
|
||||
|
||||
// Sometimes we emulate renderbuffers (depth-stencil emu), so there's not
|
||||
// always a 1-1 mapping from `wrb` to GL name. Just have `wrb` handle it.
|
||||
if (wrb) {
|
||||
wrb->BindRenderbuffer();
|
||||
#ifdef ANDROID
|
||||
wrb->mIsRB = true;
|
||||
#endif
|
||||
} else {
|
||||
gl->fBindRenderbuffer(target, 0);
|
||||
wrb->mHasBeenBound = true;
|
||||
}
|
||||
|
||||
mBoundRenderbuffer = wrb;
|
||||
|
@ -1068,16 +1064,7 @@ WebGLContext::IsRenderbuffer(WebGLRenderbuffer* rb)
|
|||
if (rb->IsDeleted())
|
||||
return false;
|
||||
|
||||
#ifdef ANDROID
|
||||
if (gl->WorkAroundDriverBugs() &&
|
||||
gl->Renderer() == GLRenderer::AndroidEmulator)
|
||||
{
|
||||
return rb->mIsRB;
|
||||
}
|
||||
#endif
|
||||
|
||||
MakeContextCurrent();
|
||||
return gl->fIsRenderbuffer(rb->PrimaryGLName());
|
||||
return rb->mHasBeenBound;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1799,66 +1786,41 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
|
|||
|
||||
void
|
||||
WebGLContext::RenderbufferStorage_base(const char* funcName, GLenum target,
|
||||
GLsizei samples,
|
||||
GLenum internalFormat, GLsizei width,
|
||||
GLsizei height)
|
||||
GLsizei samples, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!mBoundRenderbuffer) {
|
||||
ErrorInvalidOperation("%s: Called on renderbuffer 0.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (target != LOCAL_GL_RENDERBUFFER) {
|
||||
ErrorInvalidEnumInfo("`target`", funcName, target);
|
||||
return;
|
||||
}
|
||||
|
||||
if (samples < 0 || samples > mGLMaxSamples) {
|
||||
ErrorInvalidValue("%s: `samples` is out of the valid range.", funcName);
|
||||
if (!mBoundRenderbuffer) {
|
||||
ErrorInvalidOperation("%s: Called on renderbuffer 0.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (samples < 0) {
|
||||
ErrorInvalidValue("%s: `samples` must be >= 0.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (width < 0 || height < 0) {
|
||||
ErrorInvalidValue("%s: Width and height must be >= 0.", funcName);
|
||||
ErrorInvalidValue("%s: `width` and `height` must be >= 0.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uint32_t(width) > mImplMaxRenderbufferSize ||
|
||||
uint32_t(height) > mImplMaxRenderbufferSize)
|
||||
{
|
||||
ErrorInvalidValue("%s: Width or height exceeds maximum renderbuffer"
|
||||
" size.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto usage = mFormatUsage->GetRBUsage(internalFormat);
|
||||
if (!usage) {
|
||||
ErrorInvalidEnumInfo("`internalFormat`", funcName, internalFormat);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validation complete.
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
mBoundRenderbuffer->RenderbufferStorage(samples, usage, width, height);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
if (error) {
|
||||
GenerateWarning("%s generated error %s", funcName,
|
||||
ErrorName(error));
|
||||
return;
|
||||
}
|
||||
mBoundRenderbuffer->RenderbufferStorage(funcName, uint32_t(samples), internalFormat,
|
||||
uint32_t(width), uint32_t(height));
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::RenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height)
|
||||
{
|
||||
RenderbufferStorage_base("renderbufferStorage", target, 0,
|
||||
internalFormat, width, height);
|
||||
RenderbufferStorage_base("renderbufferStorage", target, 0, internalFormat, width,
|
||||
height);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2323,6 +2285,8 @@ WebGLContext::CreateRenderbuffer()
|
|||
{
|
||||
if (IsContextLost())
|
||||
return nullptr;
|
||||
|
||||
MakeContextCurrent();
|
||||
RefPtr<WebGLRenderbuffer> globj = new WebGLRenderbuffer(this);
|
||||
return globj.forget();
|
||||
}
|
||||
|
|
|
@ -727,6 +727,8 @@ WebGLContext::AssertCachedBindings()
|
|||
|
||||
MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
|
||||
#endif
|
||||
|
||||
// We do not check the renderbuffer binding, because we never rely on it matching.
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -786,8 +786,6 @@ WebGLContext::InitAndValidateGL()
|
|||
|
||||
mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
|
||||
mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
|
||||
|
||||
mGLMaxSamples = 1;
|
||||
} else {
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*)&mImplMaxTextureSize);
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&mImplMaxCubeMapTextureSize);
|
||||
|
@ -800,9 +798,6 @@ WebGLContext::InitAndValidateGL()
|
|||
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
|
||||
|
||||
if (!gl->GetPotentialInteger(LOCAL_GL_MAX_SAMPLES, (GLint*)&mGLMaxSamples))
|
||||
mGLMaxSamples = 1;
|
||||
}
|
||||
|
||||
// If we don't support a target, its max size is 0. We should only floor-to-POT if the
|
||||
|
|
|
@ -416,8 +416,6 @@ BytesPerPixel(const PackingInfo& packing)
|
|||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FormatUsageAuthority
|
||||
|
||||
|
||||
|
||||
bool
|
||||
FormatUsageInfo::IsUnpackValid(const PackingInfo& key,
|
||||
const DriverUnpackInfo** const out_value) const
|
||||
|
@ -430,6 +428,29 @@ FormatUsageInfo::IsUnpackValid(const PackingInfo& key,
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FormatUsageInfo::ResolveMaxSamples(gl::GLContext* gl)
|
||||
{
|
||||
MOZ_ASSERT(!this->maxSamplesKnown);
|
||||
MOZ_ASSERT(this->maxSamples == 0);
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
this->maxSamplesKnown = true;
|
||||
|
||||
const GLenum internalFormat = this->format->sizedFormat;
|
||||
if (!internalFormat)
|
||||
return;
|
||||
|
||||
if (!gl->IsSupported(gl::GLFeature::internalformat_query))
|
||||
return; // Leave it at 0.
|
||||
|
||||
GLint maxSamplesGL = 0;
|
||||
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalFormat, LOCAL_GL_SAMPLES, 1,
|
||||
&maxSamplesGL);
|
||||
|
||||
this->maxSamples = maxSamplesGL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
static void
|
||||
|
|
|
@ -248,10 +248,15 @@ struct FormatUsageInfo
|
|||
const FormatInfo* const format;
|
||||
bool isRenderable;
|
||||
bool isFilterable;
|
||||
|
||||
std::map<PackingInfo, DriverUnpackInfo> validUnpacks;
|
||||
const DriverUnpackInfo* idealUnpack;
|
||||
|
||||
const GLint* textureSwizzleRGBA;
|
||||
|
||||
bool maxSamplesKnown;
|
||||
uint32_t maxSamples;
|
||||
|
||||
static const GLint kLuminanceSwizzleRGBA[4];
|
||||
static const GLint kAlphaSwizzleRGBA[4];
|
||||
static const GLint kLumAlphaSwizzleRGBA[4];
|
||||
|
@ -262,10 +267,14 @@ struct FormatUsageInfo
|
|||
, isFilterable(false)
|
||||
, idealUnpack(nullptr)
|
||||
, textureSwizzleRGBA(nullptr)
|
||||
, maxSamplesKnown(false)
|
||||
, maxSamples(0)
|
||||
{ }
|
||||
|
||||
bool IsUnpackValid(const PackingInfo& key,
|
||||
const DriverUnpackInfo** const out_value) const;
|
||||
|
||||
void ResolveMaxSamples(gl::GLContext* gl);
|
||||
};
|
||||
|
||||
class FormatUsageAuthority
|
||||
|
|
|
@ -69,6 +69,17 @@ WebGLFBAttachPoint::Format() const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
WebGLFBAttachPoint::Samples() const
|
||||
{
|
||||
MOZ_ASSERT(IsDefined());
|
||||
|
||||
if (mRenderbufferPtr)
|
||||
return mRenderbufferPtr->Samples();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLFBAttachPoint::HasAlpha() const
|
||||
{
|
||||
|
@ -394,11 +405,11 @@ WebGLFBAttachPoint::FinalizeAttachment(gl::GLContext* gl, GLenum attachment) con
|
|||
}
|
||||
break;
|
||||
}
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Renderbuffer()) {
|
||||
Renderbuffer()->FramebufferRenderbuffer(attachment);
|
||||
Renderbuffer()->DoFramebufferRenderbuffer(attachment);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -790,28 +801,6 @@ WebGLFramebuffer::HasIncompleteAttachments(nsCString* const out_info) const
|
|||
return hasIncomplete;
|
||||
}
|
||||
|
||||
static bool
|
||||
MatchOrReplaceSize(const WebGLFBAttachPoint& cur, uint32_t* const out_width,
|
||||
uint32_t* const out_height)
|
||||
{
|
||||
if (!cur.HasImage())
|
||||
return true;
|
||||
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
cur.Size(&width, &height);
|
||||
|
||||
if (!*out_width) {
|
||||
MOZ_ASSERT(!*out_height);
|
||||
*out_width = width;
|
||||
*out_height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
return (width == *out_width &&
|
||||
height == *out_height);
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLFramebuffer::AllImageRectsMatch() const
|
||||
{
|
||||
|
@ -819,20 +808,84 @@ WebGLFramebuffer::AllImageRectsMatch() const
|
|||
DebugOnly<nsCString> fbStatusInfo;
|
||||
MOZ_ASSERT(!HasIncompleteAttachments(&fbStatusInfo));
|
||||
|
||||
bool needsInit = true;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
bool imageRectsMatch = true;
|
||||
|
||||
imageRectsMatch &= MatchOrReplaceSize(mColorAttachment0, &width, &height);
|
||||
imageRectsMatch &= MatchOrReplaceSize(mDepthAttachment, &width, &height);
|
||||
imageRectsMatch &= MatchOrReplaceSize(mStencilAttachment, &width, &height);
|
||||
imageRectsMatch &= MatchOrReplaceSize(mDepthStencilAttachment, &width, &height);
|
||||
const auto fnInitializeOrMatch = [&needsInit, &width,
|
||||
&height](const WebGLFBAttachPoint& attach)
|
||||
{
|
||||
if (!attach.HasImage())
|
||||
return true;
|
||||
|
||||
uint32_t curWidth;
|
||||
uint32_t curHeight;
|
||||
attach.Size(&curWidth, &curHeight);
|
||||
|
||||
if (needsInit) {
|
||||
needsInit = false;
|
||||
width = curWidth;
|
||||
height = curHeight;
|
||||
return true;
|
||||
}
|
||||
|
||||
return (curWidth == width &&
|
||||
curHeight == height);
|
||||
};
|
||||
|
||||
bool matches = true;
|
||||
|
||||
matches &= fnInitializeOrMatch(mColorAttachment0 );
|
||||
matches &= fnInitializeOrMatch(mDepthAttachment );
|
||||
matches &= fnInitializeOrMatch(mStencilAttachment );
|
||||
matches &= fnInitializeOrMatch(mDepthStencilAttachment);
|
||||
|
||||
for (const auto& cur : mMoreColorAttachments) {
|
||||
imageRectsMatch &= MatchOrReplaceSize(cur, &width, &height);
|
||||
matches &= fnInitializeOrMatch(cur);
|
||||
}
|
||||
|
||||
return imageRectsMatch;
|
||||
return matches;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLFramebuffer::AllImageSamplesMatch() const
|
||||
{
|
||||
MOZ_ASSERT(HasDefinedAttachments());
|
||||
DebugOnly<nsCString> fbStatusInfo;
|
||||
MOZ_ASSERT(!HasIncompleteAttachments(&fbStatusInfo));
|
||||
|
||||
bool needsInit = true;
|
||||
uint32_t samples = 0;
|
||||
|
||||
const auto fnInitializeOrMatch = [&needsInit,
|
||||
&samples](const WebGLFBAttachPoint& attach)
|
||||
{
|
||||
if (!attach.HasImage())
|
||||
return true;
|
||||
|
||||
const uint32_t curSamples = attach.Samples();
|
||||
|
||||
if (needsInit) {
|
||||
needsInit = false;
|
||||
samples = curSamples;
|
||||
return true;
|
||||
}
|
||||
|
||||
return (curSamples == samples);
|
||||
};
|
||||
|
||||
bool matches = true;
|
||||
|
||||
matches &= fnInitializeOrMatch(mColorAttachment0 );
|
||||
matches &= fnInitializeOrMatch(mDepthAttachment );
|
||||
matches &= fnInitializeOrMatch(mStencilAttachment );
|
||||
matches &= fnInitializeOrMatch(mDepthStencilAttachment);
|
||||
|
||||
for (const auto& cur : mMoreColorAttachments) {
|
||||
matches &= fnInitializeOrMatch(cur);
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
FBStatus
|
||||
|
@ -850,7 +903,11 @@ WebGLFramebuffer::PrecheckFramebufferStatus(nsCString* const out_info) const
|
|||
if (!AllImageRectsMatch())
|
||||
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; // Inconsistent sizes
|
||||
|
||||
if (!AllImageSamplesMatch())
|
||||
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; // Inconsistent samples
|
||||
|
||||
if (!mContext->IsWebGL2()) {
|
||||
// INCOMPLETE_DIMENSIONS doesn't exist in GLES3.
|
||||
const auto depthOrStencilCount = int(mDepthAttachment.IsDefined()) +
|
||||
int(mStencilAttachment.IsDefined()) +
|
||||
int(mDepthStencilAttachment.IsDefined());
|
||||
|
|
|
@ -49,7 +49,6 @@ private:
|
|||
, mAttachmentPoint(0)
|
||||
{ }
|
||||
|
||||
|
||||
public:
|
||||
WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
|
||||
~WebGLFBAttachPoint();
|
||||
|
@ -60,6 +59,7 @@ public:
|
|||
bool IsDeleteRequested() const;
|
||||
|
||||
const webgl::FormatUsageInfo* Format() const;
|
||||
uint32_t Samples() const;
|
||||
|
||||
bool HasAlpha() const;
|
||||
bool IsReadableFloat() const;
|
||||
|
@ -98,7 +98,6 @@ public:
|
|||
void SetImageDataStatus(WebGLImageDataStatus x);
|
||||
|
||||
void Size(uint32_t* const out_width, uint32_t* const out_height) const;
|
||||
//const WebGLRectangleObject& RectangleObject() const;
|
||||
|
||||
bool HasImage() const;
|
||||
bool IsComplete(WebGLContext* webgl, nsCString* const out_info) const;
|
||||
|
@ -229,6 +228,7 @@ public:
|
|||
bool HasDefinedAttachments() const;
|
||||
bool HasIncompleteAttachments(nsCString* const out_info) const;
|
||||
bool AllImageRectsMatch() const;
|
||||
bool AllImageSamplesMatch() const;
|
||||
FBStatus PrecheckFramebufferStatus(nsCString* const out_info) const;
|
||||
FBStatus CheckFramebufferStatus(nsCString* const out_info) const;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
namespace mozilla {
|
||||
|
||||
static GLenum
|
||||
DepthStencilDepthFormat(gl::GLContext* gl)
|
||||
DepthFormatForDepthStencilEmu(gl::GLContext* gl)
|
||||
{
|
||||
// We might not be able to get 24-bit, so let's pretend!
|
||||
if (gl->IsGLES() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
|
||||
|
@ -24,46 +24,38 @@ DepthStencilDepthFormat(gl::GLContext* gl)
|
|||
return LOCAL_GL_DEPTH_COMPONENT24;
|
||||
}
|
||||
|
||||
static bool
|
||||
NeedsDepthStencilEmu(gl::GLContext* gl, GLenum internalFormat)
|
||||
{
|
||||
MOZ_ASSERT(internalFormat != LOCAL_GL_DEPTH_STENCIL);
|
||||
|
||||
if (internalFormat != LOCAL_GL_DEPTH24_STENCIL8)
|
||||
return false;
|
||||
|
||||
if (gl->IsSupported(gl::GLFeature::packed_depth_stencil))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WebGLRenderbuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
|
||||
{
|
||||
return dom::WebGLRenderbufferBinding::Wrap(cx, this, givenProto);
|
||||
}
|
||||
|
||||
static GLuint
|
||||
DoCreateRenderbuffer(gl::GLContext* gl)
|
||||
{
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
GLuint ret = 0;
|
||||
gl->fGenRenderbuffers(1, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
EmulatePackedDepthStencil(gl::GLContext* gl)
|
||||
{
|
||||
return !gl->IsSupported(gl::GLFeature::packed_depth_stencil);
|
||||
}
|
||||
|
||||
WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext* webgl)
|
||||
: WebGLContextBoundObject(webgl)
|
||||
, mPrimaryRB(0)
|
||||
, mPrimaryRB( DoCreateRenderbuffer(webgl->gl) )
|
||||
, mEmulatePackedDepthStencil( EmulatePackedDepthStencil(webgl->gl) )
|
||||
, mSecondaryRB(0)
|
||||
, mFormat(nullptr)
|
||||
, mSamples(0)
|
||||
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
|
||||
, mSamples(1)
|
||||
, mIsUsingSecondary(false)
|
||||
#ifdef ANDROID
|
||||
, mIsRB(false)
|
||||
#endif
|
||||
, mHasBeenBound(false)
|
||||
{
|
||||
mContext->MakeContextCurrent();
|
||||
|
||||
mContext->gl->fGenRenderbuffers(1, &mPrimaryRB);
|
||||
|
||||
if (!mContext->gl->IsSupported(gl::GLFeature::packed_depth_stencil)) {
|
||||
mContext->gl->fGenRenderbuffers(1, &mSecondaryRB);
|
||||
}
|
||||
|
||||
mContext->mRenderbuffers.insertBack(this);
|
||||
}
|
||||
|
||||
|
@ -77,9 +69,6 @@ WebGLRenderbuffer::Delete()
|
|||
mContext->gl->fDeleteRenderbuffers(1, &mSecondaryRB);
|
||||
|
||||
LinkedListElement<WebGLRenderbuffer>::removeFrom(mContext->mRenderbuffers);
|
||||
#ifdef ANDROID
|
||||
mIsRB = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
@ -89,156 +78,173 @@ WebGLRenderbuffer::MemoryUsage() const
|
|||
if (!mFormat)
|
||||
return 0;
|
||||
|
||||
auto bytesPerPixel = mFormat->format->estimatedBytesPerPixel;
|
||||
uint64_t pixels = uint64_t(mWidth) * uint64_t(mHeight);
|
||||
const auto bytesPerPixel = mFormat->format->estimatedBytesPerPixel;
|
||||
const int64_t pixels = int64_t(mWidth) * int64_t(mHeight);
|
||||
|
||||
uint64_t totalSize = pixels * bytesPerPixel;
|
||||
|
||||
// If we have the same bytesPerPixel whether or not we have a secondary RB.
|
||||
if (mSecondaryRB && !mIsUsingSecondary) {
|
||||
totalSize += 2; // 1x1xRGBA4
|
||||
}
|
||||
|
||||
return int64_t(totalSize);
|
||||
const int64_t totalSize = pixels * bytesPerPixel;
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLRenderbuffer::BindRenderbuffer() const
|
||||
{
|
||||
/* Do this explicitly here, since the meaning changes for depth-stencil emu.
|
||||
* Under normal circumstances, there's only one RB: `mPrimaryRB`.
|
||||
* `mSecondaryRB` is used when we have to pretend that the renderbuffer is
|
||||
* DEPTH_STENCIL, when it's actually one DEPTH buffer `mPrimaryRB` and one
|
||||
* STENCIL buffer `mSecondaryRB`.
|
||||
*
|
||||
* In the DEPTH_STENCIL emulation case, we're actually juggling two RBs, but
|
||||
* we can only bind one of them at a time. We choose to unconditionally bind
|
||||
* the depth RB. When we need to ask about the stencil buffer (say, how many
|
||||
* stencil bits we have), we temporarily bind the stencil RB, so that it
|
||||
* looks like we're just asking the question of a combined DEPTH_STENCIL
|
||||
* buffer.
|
||||
*/
|
||||
mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
|
||||
}
|
||||
|
||||
static void
|
||||
RenderbufferStorageMaybeMultisample(gl::GLContext* gl, GLsizei samples,
|
||||
GLenum internalFormat, GLsizei width,
|
||||
GLsizei height)
|
||||
static GLenum
|
||||
DoRenderbufferStorageMaybeMultisample(gl::GLContext* gl, GLsizei samples,
|
||||
GLenum internalFormat, GLsizei width,
|
||||
GLsizei height)
|
||||
{
|
||||
MOZ_ASSERT_IF(samples >= 1, gl->IsSupported(gl::GLFeature::framebuffer_multisample));
|
||||
MOZ_ASSERT(samples >= 0);
|
||||
MOZ_ASSERT(samples <= gl->MaxSamples());
|
||||
|
||||
// certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
|
||||
GLenum internalFormatForGL = internalFormat;
|
||||
|
||||
// Certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL.
|
||||
switch (internalFormat) {
|
||||
case LOCAL_GL_RGBA4:
|
||||
case LOCAL_GL_RGB5_A1:
|
||||
// 16-bit RGBA formats are not supported on desktop GL
|
||||
// 16-bit RGBA formats are not supported on desktop GL.
|
||||
if (!gl->IsGLES())
|
||||
internalFormatForGL = LOCAL_GL_RGBA8;
|
||||
internalFormat = LOCAL_GL_RGBA8;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_RGB565:
|
||||
// the RGB565 format is not supported on desktop GL
|
||||
// RGB565 is not supported on desktop GL.
|
||||
if (!gl->IsGLES())
|
||||
internalFormatForGL = LOCAL_GL_RGB8;
|
||||
internalFormat = LOCAL_GL_RGB8;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_DEPTH_COMPONENT16:
|
||||
if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
|
||||
internalFormatForGL = LOCAL_GL_DEPTH_COMPONENT24;
|
||||
internalFormat = LOCAL_GL_DEPTH_COMPONENT24;
|
||||
else if (gl->IsSupported(gl::GLFeature::packed_depth_stencil))
|
||||
internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
|
||||
internalFormat = LOCAL_GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_DEPTH_STENCIL:
|
||||
// We emulate this in WebGLRenderbuffer if we don't have the requisite extension.
|
||||
internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
|
||||
MOZ_CRASH("GL_DEPTH_STENCIL is not valid here.");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
gl::GLContext::LocalErrorScope errorScope(*gl);
|
||||
|
||||
if (samples > 0) {
|
||||
gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples,
|
||||
internalFormatForGL, width, height);
|
||||
internalFormat, width, height);
|
||||
} else {
|
||||
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormatForGL, width,
|
||||
height);
|
||||
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormat, width, height);
|
||||
}
|
||||
|
||||
return errorScope.GetError();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLRenderbuffer::RenderbufferStorage(GLsizei samples,
|
||||
const webgl::FormatUsageInfo* format,
|
||||
GLsizei width, GLsizei height)
|
||||
GLenum
|
||||
WebGLRenderbuffer::DoRenderbufferStorage(uint32_t samples,
|
||||
const webgl::FormatUsageInfo* format,
|
||||
uint32_t width, uint32_t height)
|
||||
{
|
||||
MOZ_ASSERT(mContext->mBoundRenderbuffer == this);
|
||||
|
||||
|
||||
gl::GLContext* gl = mContext->gl;
|
||||
MOZ_ASSERT(samples >= 0 && samples <= 256); // Sanity check.
|
||||
MOZ_ASSERT(samples <= 256); // Sanity check.
|
||||
|
||||
GLenum primaryFormat = format->format->sizedFormat;
|
||||
GLenum secondaryFormat = 0;
|
||||
|
||||
if (NeedsDepthStencilEmu(mContext->gl, primaryFormat)) {
|
||||
primaryFormat = DepthStencilDepthFormat(gl);
|
||||
if (mEmulatePackedDepthStencil && primaryFormat == LOCAL_GL_DEPTH24_STENCIL8) {
|
||||
primaryFormat = DepthFormatForDepthStencilEmu(gl);
|
||||
secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
|
||||
}
|
||||
|
||||
RenderbufferStorageMaybeMultisample(gl, samples, primaryFormat, width,
|
||||
height);
|
||||
gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
|
||||
GLenum error = DoRenderbufferStorageMaybeMultisample(gl, samples, primaryFormat,
|
||||
width, height);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (mSecondaryRB) {
|
||||
// We can't leave the secondary RB unspecified either, since we should
|
||||
// handle the case where we attach a non-depth-stencil RB to a
|
||||
// depth-stencil attachment point, or attach this depth-stencil RB to a
|
||||
// non-depth-stencil attachment point.
|
||||
gl::ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
|
||||
if (secondaryFormat) {
|
||||
RenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat, width,
|
||||
height);
|
||||
} else {
|
||||
RenderbufferStorageMaybeMultisample(gl, samples, LOCAL_GL_RGBA4, 1, 1);
|
||||
if (secondaryFormat) {
|
||||
if (!mSecondaryRB) {
|
||||
gl->fGenRenderbuffers(1, &mSecondaryRB);
|
||||
}
|
||||
|
||||
gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mSecondaryRB);
|
||||
error = DoRenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat,
|
||||
width, height);
|
||||
if (error)
|
||||
return error;
|
||||
} else if (mSecondaryRB) {
|
||||
gl->fDeleteRenderbuffers(1, &mSecondaryRB);
|
||||
mSecondaryRB = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples,
|
||||
GLenum internalFormat, uint32_t width,
|
||||
uint32_t height)
|
||||
{
|
||||
const auto usage = mContext->mFormatUsage->GetRBUsage(internalFormat);
|
||||
if (!usage) {
|
||||
mContext->ErrorInvalidEnum("%s: Invalid `internalFormat`: 0x%04x.", funcName,
|
||||
internalFormat);
|
||||
return;
|
||||
}
|
||||
|
||||
if (width > mContext->mImplMaxRenderbufferSize ||
|
||||
height > mContext->mImplMaxRenderbufferSize)
|
||||
{
|
||||
mContext->ErrorInvalidValue("%s: Width or height exceeds maximum renderbuffer"
|
||||
" size.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
|
||||
if (!usage->maxSamplesKnown) {
|
||||
const_cast<webgl::FormatUsageInfo*>(usage)->ResolveMaxSamples(mContext->gl);
|
||||
}
|
||||
MOZ_ASSERT(usage->maxSamplesKnown);
|
||||
|
||||
if (samples > usage->maxSamples) {
|
||||
mContext->ErrorInvalidValue("%s: `samples` is out of the valid range.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validation complete.
|
||||
|
||||
const GLenum error = DoRenderbufferStorage(samples, usage, width, height);
|
||||
if (error) {
|
||||
const char* errorName = mContext->ErrorName(error);
|
||||
mContext->GenerateWarning("%s generated error %s", funcName, errorName);
|
||||
return;
|
||||
}
|
||||
|
||||
mSamples = samples;
|
||||
mFormat = format;
|
||||
mFormat = usage;
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;
|
||||
mIsUsingSecondary = bool(secondaryFormat);
|
||||
|
||||
InvalidateStatusOfAttachedFBs();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLRenderbuffer::FramebufferRenderbuffer(GLenum attachment) const
|
||||
WebGLRenderbuffer::DoFramebufferRenderbuffer(GLenum attachment) const
|
||||
{
|
||||
gl::GLContext* gl = mContext->gl;
|
||||
if (attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment,
|
||||
|
||||
if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
const GLuint stencilRB = (mSecondaryRB ? mSecondaryRB : mPrimaryRB);
|
||||
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_DEPTH_ATTACHMENT,
|
||||
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
|
||||
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_STENCIL_ATTACHMENT,
|
||||
LOCAL_GL_RENDERBUFFER, stencilRB);
|
||||
return;
|
||||
}
|
||||
|
||||
GLuint stencilRB = mPrimaryRB;
|
||||
if (mIsUsingSecondary) {
|
||||
MOZ_ASSERT(mSecondaryRB);
|
||||
stencilRB = mSecondaryRB;
|
||||
}
|
||||
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_DEPTH_ATTACHMENT,
|
||||
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment,
|
||||
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
|
||||
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_STENCIL_ATTACHMENT,
|
||||
LOCAL_GL_RENDERBUFFER, stencilRB);
|
||||
}
|
||||
|
||||
GLint
|
||||
|
@ -266,6 +272,7 @@ WebGLRenderbuffer::GetRenderbufferParameter(RBTarget target,
|
|||
case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
|
||||
case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
|
||||
{
|
||||
gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
|
||||
GLint i = 0;
|
||||
gl->fGetRenderbufferParameteriv(target.get(), pname.get(), &i);
|
||||
return i;
|
||||
|
@ -285,8 +292,7 @@ WebGLRenderbuffer::GetRenderbufferParameter(RBTarget target,
|
|||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false,
|
||||
"This function should only be called with valid `pname`.");
|
||||
MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,26 @@ class WebGLRenderbuffer final
|
|||
, public WebGLContextBoundObject
|
||||
, public WebGLFramebufferAttachable
|
||||
{
|
||||
friend class WebGLContext;
|
||||
friend class WebGLFramebuffer;
|
||||
friend class WebGLFBAttachPoint;
|
||||
|
||||
public:
|
||||
const GLuint mPrimaryRB;
|
||||
protected:
|
||||
const bool mEmulatePackedDepthStencil;
|
||||
GLuint mSecondaryRB;
|
||||
const webgl::FormatUsageInfo* mFormat;
|
||||
GLsizei mSamples;
|
||||
|
||||
WebGLImageDataStatus mImageDataStatus;
|
||||
|
||||
bool mHasBeenBound;
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbuffer)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLRenderbuffer)
|
||||
|
||||
explicit WebGLRenderbuffer(WebGLContext* webgl);
|
||||
|
||||
void Delete();
|
||||
|
@ -46,8 +65,6 @@ public:
|
|||
|
||||
GLsizei Samples() const { return mSamples; }
|
||||
|
||||
GLuint PrimaryGLName() const { return mPrimaryRB; }
|
||||
|
||||
const webgl::FormatUsageInfo* Format() const { return mFormat; }
|
||||
|
||||
int64_t MemoryUsage() const;
|
||||
|
@ -56,41 +73,21 @@ public:
|
|||
return mContext;
|
||||
}
|
||||
|
||||
void BindRenderbuffer() const;
|
||||
void RenderbufferStorage(GLsizei samples, const webgl::FormatUsageInfo* format,
|
||||
GLsizei width, GLsizei height);
|
||||
void FramebufferRenderbuffer(GLenum attachment) const;
|
||||
void RenderbufferStorage(const char* funcName, uint32_t samples,
|
||||
GLenum internalFormat, uint32_t width, uint32_t height);
|
||||
// Only handles a subset of `pname`s.
|
||||
GLint GetRenderbufferParameter(RBTarget target, RBParam pname) const;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbuffer)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLRenderbuffer)
|
||||
|
||||
protected:
|
||||
~WebGLRenderbuffer() {
|
||||
DeleteOnce();
|
||||
}
|
||||
|
||||
GLuint mPrimaryRB;
|
||||
GLuint mSecondaryRB;
|
||||
const webgl::FormatUsageInfo* mFormat;
|
||||
WebGLImageDataStatus mImageDataStatus;
|
||||
GLsizei mSamples;
|
||||
bool mIsUsingSecondary;
|
||||
#ifdef ANDROID
|
||||
// Bug 1140459: Some drivers (including our test slaves!) don't
|
||||
// give reasonable answers for IsRenderbuffer, maybe others.
|
||||
// This shows up on Android 2.3 emulator.
|
||||
//
|
||||
// So we track the `is a Renderbuffer` state ourselves.
|
||||
bool mIsRB;
|
||||
#endif
|
||||
|
||||
friend class WebGLContext;
|
||||
friend class WebGLFramebuffer;
|
||||
friend class WebGLFBAttachPoint;
|
||||
void DoFramebufferRenderbuffer(GLenum attachment) const;
|
||||
GLenum DoRenderbufferStorage(uint32_t samples, const webgl::FormatUsageInfo* format,
|
||||
uint32_t width, uint32_t height);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<html>
|
||||
<head>
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
var canvas = document.getElementById("canvas");
|
||||
var ctx = SpecialPowers.wrap(canvas.getContext("2d"));
|
||||
ctx.drawWindow(window, 0, 0, canvas.width, canvas.height, "red");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();">
|
||||
<canvas id="canvas" width="10" height="10"></canvas>
|
||||
</body>
|
||||
</html>
|
|
@ -29,4 +29,5 @@ skip-if(azureCairo) load 1229983-1.html
|
|||
load 1229932-1.html
|
||||
load 1233613.html
|
||||
load 1244850-1.html
|
||||
load 1246775-1.html
|
||||
load texImage2D.html
|
||||
|
|
|
@ -194,7 +194,6 @@ TouchEvent::PrefEnabled(JSContext* aCx, JSObject* aGlobal)
|
|||
}
|
||||
prefValue = sIsTouchDeviceSupportPresent;
|
||||
#else
|
||||
NS_WARNING("dom.w3c_touch_events.enabled=2 not implemented!");
|
||||
prefValue = false;
|
||||
#endif
|
||||
} else {
|
||||
|
|
|
@ -487,20 +487,6 @@ MediaSource::NotifyEvicted(double aStart, double aEnd)
|
|||
mSourceBuffers->Evict(aStart, aEnd);
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
void
|
||||
MediaSource::Dump(const char* aPath)
|
||||
{
|
||||
char buf[255];
|
||||
PR_snprintf(buf, sizeof(buf), "%s/mediasource-%p", aPath, this);
|
||||
PR_MkDir(buf, 0700);
|
||||
|
||||
if (mSourceBuffers) {
|
||||
mSourceBuffers->Dump(buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
MediaSource::GetMozDebugReaderData(nsAString& aString)
|
||||
{
|
||||
|
|
|
@ -100,12 +100,6 @@ public:
|
|||
// that were evicted are provided.
|
||||
void NotifyEvicted(double aStart, double aEnd);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// Dump the contents of each SourceBuffer to a series of files under aPath.
|
||||
// aPath must exist. Debug only, invoke from your favourite debugger.
|
||||
void Dump(const char* aPath);
|
||||
#endif
|
||||
|
||||
// Returns a string describing the state of the MediaSource internal
|
||||
// buffered data. Used for debugging purposes.
|
||||
void GetMozDebugReaderData(nsAString& aString);
|
||||
|
|
|
@ -256,6 +256,12 @@ MediaDecoderOwner::NextFrameStatus
|
|||
MediaSourceDecoder::NextFrameBufferedStatus()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mMediaSource ||
|
||||
mMediaSource->ReadyState() == dom::MediaSourceReadyState::Closed) {
|
||||
return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
|
||||
}
|
||||
|
||||
// Next frame hasn't been decoded yet.
|
||||
// Use the buffered range to consider if we have the next frame available.
|
||||
TimeUnit currentPosition = TimeUnit::FromMicroseconds(CurrentPosition());
|
||||
|
|
|
@ -22,7 +22,7 @@ using media::TimeIntervals;
|
|||
|
||||
MediaSourceDemuxer::MediaSourceDemuxer()
|
||||
: mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
|
||||
/* aSupportsTailDispatch = */ true))
|
||||
/* aSupportsTailDispatch = */ false))
|
||||
, mMonitor("MediaSourceDemuxer")
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
|
|
@ -39,27 +39,6 @@ using media::TimeUnit;
|
|||
|
||||
namespace dom {
|
||||
|
||||
class BufferAppendRunnable : public nsRunnable {
|
||||
public:
|
||||
BufferAppendRunnable(SourceBuffer* aSourceBuffer,
|
||||
uint32_t aUpdateID)
|
||||
: mSourceBuffer(aSourceBuffer)
|
||||
, mUpdateID(aUpdateID)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override final {
|
||||
|
||||
mSourceBuffer->BufferAppend(mUpdateID);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<SourceBuffer> mSourceBuffer;
|
||||
uint32_t mUpdateID;
|
||||
};
|
||||
|
||||
void
|
||||
SourceBuffer::SetMode(SourceBufferAppendMode aMode, ErrorResult& aRv)
|
||||
{
|
||||
|
@ -226,10 +205,13 @@ void
|
|||
SourceBuffer::AbortBufferAppend()
|
||||
{
|
||||
if (mUpdating) {
|
||||
mPendingAppend.DisconnectIfExists();
|
||||
// TODO: Abort stream append loop algorithms.
|
||||
// cancel any pending buffer append.
|
||||
mContentManager->AbortAppendData();
|
||||
if (mPendingAppend.Exists()) {
|
||||
mPendingAppend.Disconnect();
|
||||
mContentManager->AbortAppendData();
|
||||
// Some data may have been added by the Segment Parser Loop.
|
||||
// Check if we need to update the duration.
|
||||
CheckEndTime();
|
||||
}
|
||||
AbortUpdating();
|
||||
}
|
||||
}
|
||||
|
@ -309,7 +291,6 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
|
|||
, mMediaSource(aMediaSource)
|
||||
, mUpdating(false)
|
||||
, mActive(false)
|
||||
, mUpdateID(0)
|
||||
, mType(aType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -381,7 +362,6 @@ SourceBuffer::StartUpdating()
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mUpdating);
|
||||
mUpdating = true;
|
||||
mUpdateID++;
|
||||
QueueAsyncSimpleEvent("updatestart");
|
||||
}
|
||||
|
||||
|
@ -390,12 +370,8 @@ SourceBuffer::StopUpdating()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mUpdating) {
|
||||
// The buffer append algorithm has been interrupted by abort().
|
||||
//
|
||||
// If the sequence appendBuffer(), abort(), appendBuffer() occurs before
|
||||
// the first StopUpdating() runnable runs, then a second StopUpdating()
|
||||
// runnable will be scheduled, but still only one (the first) will queue
|
||||
// events.
|
||||
// The buffer append or range removal algorithm has been interrupted by
|
||||
// abort().
|
||||
return;
|
||||
}
|
||||
mUpdating = false;
|
||||
|
@ -407,7 +383,6 @@ void
|
|||
SourceBuffer::AbortUpdating()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mUpdating);
|
||||
mUpdating = false;
|
||||
QueueAsyncSimpleEvent("abort");
|
||||
QueueAsyncSimpleEvent("updateend");
|
||||
|
@ -438,23 +413,13 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
|||
|
||||
StartUpdating();
|
||||
|
||||
nsCOMPtr<nsIRunnable> task = new BufferAppendRunnable(this, mUpdateID);
|
||||
NS_DispatchToMainThread(task);
|
||||
BufferAppend();
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::BufferAppend(uint32_t aUpdateID)
|
||||
SourceBuffer::BufferAppend()
|
||||
{
|
||||
if (!mUpdating || aUpdateID != mUpdateID) {
|
||||
// The buffer append algorithm has been interrupted by abort().
|
||||
//
|
||||
// If the sequence appendBuffer(), abort(), appendBuffer() occurs before
|
||||
// the first StopUpdating() runnable runs, then a second StopUpdating()
|
||||
// runnable will be scheduled, but still only one (the first) will queue
|
||||
// events.
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mUpdating);
|
||||
MOZ_ASSERT(mMediaSource);
|
||||
MOZ_ASSERT(!mPendingAppend.Exists());
|
||||
|
||||
|
@ -467,11 +432,8 @@ SourceBuffer::BufferAppend(uint32_t aUpdateID)
|
|||
void
|
||||
SourceBuffer::AppendDataCompletedWithSuccess(bool aHasActiveTracks)
|
||||
{
|
||||
MOZ_ASSERT(mUpdating);
|
||||
mPendingAppend.Complete();
|
||||
if (!mUpdating) {
|
||||
// The buffer append algorithm has been interrupted by abort().
|
||||
return;
|
||||
}
|
||||
|
||||
if (aHasActiveTracks) {
|
||||
if (!mActive) {
|
||||
|
@ -494,7 +456,9 @@ SourceBuffer::AppendDataCompletedWithSuccess(bool aHasActiveTracks)
|
|||
void
|
||||
SourceBuffer::AppendDataErrored(nsresult aError)
|
||||
{
|
||||
MOZ_ASSERT(mUpdating);
|
||||
mPendingAppend.Complete();
|
||||
|
||||
switch (aError) {
|
||||
case NS_ERROR_ABORT:
|
||||
// Nothing further to do as the trackbuffer has been shutdown.
|
||||
|
@ -510,10 +474,7 @@ void
|
|||
SourceBuffer::AppendError(bool aDecoderError)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mUpdating) {
|
||||
// The buffer append algorithm has been interrupted by abort().
|
||||
return;
|
||||
}
|
||||
|
||||
mContentManager->ResetParserState();
|
||||
|
||||
mUpdating = false;
|
||||
|
@ -625,16 +586,6 @@ SourceBuffer::Evict(double aStart, double aEnd)
|
|||
mContentManager->EvictBefore(TimeUnit::FromSeconds(evictTime));
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
void
|
||||
SourceBuffer::Dump(const char* aPath)
|
||||
{
|
||||
if (mContentManager) {
|
||||
mContentManager->Dump(aPath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(SourceBuffer)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SourceBuffer)
|
||||
|
|
|
@ -213,10 +213,6 @@ public:
|
|||
return mActive;
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Dump(const char* aPath);
|
||||
#endif
|
||||
|
||||
private:
|
||||
~SourceBuffer();
|
||||
|
||||
|
@ -238,7 +234,7 @@ private:
|
|||
|
||||
// Shared implementation of AppendBuffer overloads.
|
||||
void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
|
||||
void BufferAppend(uint32_t aAppendID);
|
||||
void BufferAppend();
|
||||
|
||||
// Implement the "Append Error Algorithm".
|
||||
// Will call endOfStream() with "decode" error if aDecodeError is true.
|
||||
|
@ -266,11 +262,6 @@ private:
|
|||
|
||||
mozilla::Atomic<bool> mActive;
|
||||
|
||||
// Each time mUpdating is set to true, mUpdateID will be incremented.
|
||||
// This allows for a queued AppendData task to identify if it was earlier
|
||||
// aborted and another AppendData queued.
|
||||
uint32_t mUpdateID;
|
||||
|
||||
MozPromiseRequestHolder<SourceBufferContentManager::AppendPromise> mPendingAppend;
|
||||
const nsCString mType;
|
||||
|
||||
|
|
|
@ -108,10 +108,6 @@ public:
|
|||
virtual void RestartGroupStartTimestamp() {}
|
||||
virtual media::TimeUnit GroupEndTimestamp() = 0;
|
||||
|
||||
#if defined(DEBUG)
|
||||
virtual void Dump(const char* aPath) { }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual ~SourceBufferContentManager() { }
|
||||
};
|
||||
|
|
|
@ -176,16 +176,6 @@ SourceBufferList::QueueAsyncSimpleEvent(const char* aName)
|
|||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
void
|
||||
SourceBufferList::Dump(const char* aPath)
|
||||
{
|
||||
for (uint32_t i = 0; i < mSourceBuffers.Length(); ++i) {
|
||||
mSourceBuffers[i]->Dump(aPath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SourceBufferList::SourceBufferList(MediaSource* aMediaSource)
|
||||
: DOMEventTargetHelper(aMediaSource->GetParentObject())
|
||||
, mMediaSource(aMediaSource)
|
||||
|
|
|
@ -84,10 +84,6 @@ public:
|
|||
// No event is fired and no action is performed on the sourcebuffers.
|
||||
void ClearSimple();
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Dump(const char* aPath);
|
||||
#endif
|
||||
|
||||
private:
|
||||
~SourceBufferList();
|
||||
|
||||
|
|
|
@ -96,24 +96,17 @@ TrackBuffersManager::TrackBuffersManager(dom::SourceBufferAttributes* aAttribute
|
|||
, mType(aType)
|
||||
, mParser(ContainerParser::CreateForMIMEType(aType))
|
||||
, mProcessedInput(0)
|
||||
, mAppendRunning(false)
|
||||
, mTaskQueue(aParentDecoder->GetDemuxer()->GetTaskQueue())
|
||||
, mSourceBufferAttributes(aAttributes)
|
||||
, mParentDecoder(new nsMainThreadPtrHolder<MediaSourceDecoder>(aParentDecoder, false /* strict */))
|
||||
, mMediaSourceDuration(mTaskQueue, Maybe<double>(), "TrackBuffersManager::mMediaSourceDuration (Mirror)")
|
||||
, mAbort(false)
|
||||
, mEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold",
|
||||
100 * (1 << 20)))
|
||||
, mEvictionOccurred(false)
|
||||
, mMonitor("TrackBuffersManager")
|
||||
, mAppendRunning(false)
|
||||
, mSegmentParserLoopRunning(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread");
|
||||
RefPtr<TrackBuffersManager> self = this;
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableFunction([self] () {
|
||||
self->mMediaSourceDuration.Connect(self->mParentDecoder->CanonicalExplicitDuration());
|
||||
});
|
||||
GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
TrackBuffersManager::~TrackBuffersManager()
|
||||
|
@ -142,7 +135,6 @@ TrackBuffersManager::AppendIncomingBuffer(IncomingBuffer aData)
|
|||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
mIncomingBuffers.AppendElement(aData);
|
||||
mAbort = false;
|
||||
}
|
||||
|
||||
RefPtr<TrackBuffersManager::AppendPromise>
|
||||
|
@ -151,49 +143,42 @@ TrackBuffersManager::BufferAppend()
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("");
|
||||
|
||||
mAppendRunning = true;
|
||||
return InvokeAsync(GetTaskQueue(), this,
|
||||
__func__, &TrackBuffersManager::InitSegmentParserLoop);
|
||||
}
|
||||
|
||||
// Abort any pending AppendData.
|
||||
// We don't really care about really aborting our inner loop as by spec the
|
||||
// process is happening asynchronously, as such where and when we would abort is
|
||||
// non-deterministic. The SourceBuffer also makes sure BufferAppend
|
||||
// isn't called should the appendBuffer be immediately aborted.
|
||||
// We do however want to ensure that no new task will be dispatched on our task
|
||||
// queue and only let the current one finish its job. For this we set mAbort
|
||||
// to true.
|
||||
// The MSE spec requires that we abort the current SegmentParserLoop
|
||||
// which is then followed by a call to ResetParserState.
|
||||
// However due to our asynchronous design this causes inherent difficulities.
|
||||
// As the spec behaviour is non deterministic anyway, we instead wait until the
|
||||
// current AppendData has completed its run.
|
||||
void
|
||||
TrackBuffersManager::AbortAppendData()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("");
|
||||
|
||||
mAbort = true;
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
while (mAppendRunning) {
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffersManager::ResetParserState()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mAppendRunning, "AbortAppendData must have been called");
|
||||
MOZ_RELEASE_ASSERT(!mAppendRunning, "Append is running, abort must have been called");
|
||||
MSE_DEBUG("");
|
||||
|
||||
// 1. If the append state equals PARSING_MEDIA_SEGMENT and the input buffer contains some complete coded frames, then run the coded frame processing algorithm until all of these complete coded frames have been processed.
|
||||
if (mAppendState == AppendState::PARSING_MEDIA_SEGMENT) {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &TrackBuffersManager::FinishCodedFrameProcessing);
|
||||
GetTaskQueue()->Dispatch(task.forget());
|
||||
} else {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &TrackBuffersManager::CompleteResetParserState);
|
||||
GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
// SourceBuffer.abort() has ensured that all complete coded frames have been
|
||||
// processed. As such, we don't need to check for the value of mAppendState.
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &TrackBuffersManager::CompleteResetParserState);
|
||||
GetTaskQueue()->Dispatch(task.forget());
|
||||
|
||||
// Our ResetParserState is really asynchronous, the current task has been
|
||||
// interrupted and will complete shortly (or has already completed).
|
||||
// We must however present to the main thread a stable, reset state.
|
||||
// So we run the following operation now in the main thread.
|
||||
// 7. Set append state to WAITING_FOR_SEGMENT.
|
||||
SetAppendState(AppendState::WAITING_FOR_SEGMENT);
|
||||
}
|
||||
|
@ -202,6 +187,7 @@ RefPtr<TrackBuffersManager::RangeRemovalPromise>
|
|||
TrackBuffersManager::RangeRemoval(TimeUnit aStart, TimeUnit aEnd)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_RELEASE_ASSERT(!mAppendRunning, "Append is running");
|
||||
MSE_DEBUG("From %.2f to %.2f", aStart.ToSeconds(), aEnd.ToSeconds());
|
||||
|
||||
mEnded = false;
|
||||
|
@ -309,54 +295,13 @@ TrackBuffersManager::Detach()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("");
|
||||
|
||||
// Abort pending operations if any.
|
||||
AbortAppendData();
|
||||
|
||||
RefPtr<TrackBuffersManager> self = this;
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableFunction([self] () {
|
||||
// Clear our sourcebuffer
|
||||
self->CodedFrameRemoval(TimeInterval(TimeUnit::FromSeconds(0),
|
||||
TimeUnit::FromInfinity()));
|
||||
self->mProcessingPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
|
||||
self->mAppendPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
|
||||
self->mMediaSourceDuration.DisconnectIfConnected();
|
||||
});
|
||||
GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
void
|
||||
TrackBuffersManager::Dump(const char* aPath)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
TrackBuffersManager::FinishCodedFrameProcessing()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
if (mProcessingRequest.Exists()) {
|
||||
NS_WARNING("Processing request pending");
|
||||
mProcessingRequest.Disconnect();
|
||||
}
|
||||
// The spec requires us to complete parsing synchronously any outstanding
|
||||
// frames in the current media segment. This can't be implemented in a way
|
||||
// that makes sense.
|
||||
// As such we simply completely ignore the result of any pending input buffer.
|
||||
// TODO: Link to W3C bug.
|
||||
|
||||
CompleteResetParserState();
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffersManager::CompleteResetParserState()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(!mAppendRunning);
|
||||
MOZ_RELEASE_ASSERT(!mSegmentParserLoopRunning);
|
||||
MSE_DEBUG("");
|
||||
|
||||
for (auto& track : GetTracksList()) {
|
||||
|
@ -492,19 +437,11 @@ bool
|
|||
TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(!mAppendRunning, "Logic error: Append in progress");
|
||||
MOZ_ASSERT(!mSegmentParserLoopRunning, "Logic error: Append in progress");
|
||||
MSE_DEBUG("From %.2fs to %.2f",
|
||||
aInterval.mStart.ToSeconds(), aInterval.mEnd.ToSeconds());
|
||||
|
||||
if (mMediaSourceDuration.Ref().isNothing() ||
|
||||
IsNaN(mMediaSourceDuration.Ref().ref())) {
|
||||
MSE_DEBUG("Nothing to remove, aborting");
|
||||
return false;
|
||||
}
|
||||
TimeUnit duration{TimeUnit::FromSeconds(mMediaSourceDuration.Ref().ref())};
|
||||
|
||||
#if DEBUG
|
||||
MSE_DEBUG("duration:%.2f", duration.ToSeconds());
|
||||
if (HasVideo()) {
|
||||
MSE_DEBUG("before video ranges=%s",
|
||||
DumpTimeRanges(mVideoTracks.mBufferedRanges).get());
|
||||
|
@ -527,7 +464,14 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval)
|
|||
MSE_DEBUGV("Processing %s track", track->mInfo->mMimeType.get());
|
||||
// 1. Let remove end timestamp be the current value of duration
|
||||
// See bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=28727
|
||||
TimeUnit removeEndTimestamp = std::max(duration, track->mBufferedRanges.GetEnd());
|
||||
// At worse we will remove all frames until the end, unless a key frame is
|
||||
// found between the current interval's end and the trackbuffer's end.
|
||||
TimeUnit removeEndTimestamp = track->mBufferedRanges.GetEnd();
|
||||
|
||||
if (start > removeEndTimestamp) {
|
||||
// Nothing to remove.
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. If this track buffer has a random access point timestamp that is greater than or equal to end,
|
||||
// then update remove end timestamp to that random access point timestamp.
|
||||
|
@ -595,8 +539,9 @@ RefPtr<TrackBuffersManager::AppendPromise>
|
|||
TrackBuffersManager::InitSegmentParserLoop()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_RELEASE_ASSERT(mAppendPromise.IsEmpty());
|
||||
MSE_DEBUG("");
|
||||
|
||||
MOZ_ASSERT(mAppendPromise.IsEmpty() && !mAppendRunning);
|
||||
RefPtr<AppendPromise> p = mAppendPromise.Ensure(__func__);
|
||||
|
||||
AppendIncomingBuffers();
|
||||
|
@ -630,6 +575,9 @@ void
|
|||
TrackBuffersManager::SegmentParserLoop()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
mSegmentParserLoopRunning = true;
|
||||
|
||||
while (true) {
|
||||
// 1. If the input buffer is empty, then jump to the need more data step below.
|
||||
if (!mInputBuffer || mInputBuffer->IsEmpty()) {
|
||||
|
@ -733,7 +681,7 @@ TrackBuffersManager::SegmentParserLoop()
|
|||
->Then(GetTaskQueue(), __func__,
|
||||
[self] (bool aNeedMoreData) {
|
||||
self->mProcessingRequest.Complete();
|
||||
if (aNeedMoreData || self->mAbort) {
|
||||
if (aNeedMoreData) {
|
||||
self->NeedMoreData();
|
||||
} else {
|
||||
self->ScheduleSegmentParserLoop();
|
||||
|
@ -752,10 +700,14 @@ void
|
|||
TrackBuffersManager::NeedMoreData()
|
||||
{
|
||||
MSE_DEBUG("");
|
||||
if (!mAbort) {
|
||||
RestoreCachedVariables();
|
||||
}
|
||||
RestoreCachedVariables();
|
||||
mAppendRunning = false;
|
||||
mSegmentParserLoopRunning = false;
|
||||
{
|
||||
// Wake-up any pending Abort()
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mon.NotifyAll();
|
||||
}
|
||||
mAppendPromise.ResolveIfExists(mActiveTrack, __func__);
|
||||
}
|
||||
|
||||
|
@ -764,6 +716,12 @@ TrackBuffersManager::RejectAppend(nsresult aRejectValue, const char* aName)
|
|||
{
|
||||
MSE_DEBUG("rv=%d", aRejectValue);
|
||||
mAppendRunning = false;
|
||||
mSegmentParserLoopRunning = false;
|
||||
{
|
||||
// Wake-up any pending Abort()
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mon.NotifyAll();
|
||||
}
|
||||
mAppendPromise.RejectIfExists(aRejectValue, aName);
|
||||
}
|
||||
|
||||
|
@ -840,12 +798,7 @@ void
|
|||
TrackBuffersManager::OnDemuxerResetDone(nsresult)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
|
||||
mDemuxerInitRequest.Complete();
|
||||
if (mAbort) {
|
||||
RejectAppend(NS_ERROR_ABORT, __func__);
|
||||
return;
|
||||
}
|
||||
// mInputDemuxer shouldn't have been destroyed while a demuxer init/reset
|
||||
// request was being processed. See bug 1239983.
|
||||
MOZ_DIAGNOSTIC_ASSERT(mInputDemuxer);
|
||||
|
@ -917,13 +870,8 @@ void
|
|||
TrackBuffersManager::OnDemuxerInitDone(nsresult)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
|
||||
mDemuxerInitRequest.Complete();
|
||||
|
||||
if (mAbort) {
|
||||
RejectAppend(NS_ERROR_ABORT, __func__);
|
||||
return;
|
||||
}
|
||||
// mInputDemuxer shouldn't have been destroyed while a demuxer init/reset
|
||||
// request was being processed. See bug 1239983.
|
||||
MOZ_DIAGNOSTIC_ASSERT(mInputDemuxer);
|
||||
|
@ -1183,9 +1131,8 @@ TrackBuffersManager::OnDemuxFailed(TrackType aTrack,
|
|||
DemuxerFailureReason aFailure)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MSE_DEBUG("Failed to demux %s, failure:%d mAbort:%d",
|
||||
aTrack == TrackType::kVideoTrack ? "video" : "audio",
|
||||
aFailure, static_cast<bool>(mAbort));
|
||||
MSE_DEBUG("Failed to demux %s, failure:%d",
|
||||
aTrack == TrackType::kVideoTrack ? "video" : "audio", aFailure);
|
||||
switch (aFailure) {
|
||||
case DemuxerFailureReason::END_OF_STREAM:
|
||||
case DemuxerFailureReason::WAITING_FOR_DATA:
|
||||
|
@ -1212,15 +1159,10 @@ void
|
|||
TrackBuffersManager::DoDemuxVideo()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
|
||||
if (!HasVideo()) {
|
||||
DoDemuxAudio();
|
||||
return;
|
||||
}
|
||||
if (mAbort) {
|
||||
RejectProcessing(NS_ERROR_ABORT, __func__);
|
||||
return;
|
||||
}
|
||||
mVideoTracks.mDemuxRequest.Begin(mVideoTracks.mDemuxer->GetSamples(-1)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&TrackBuffersManager::OnVideoDemuxCompleted,
|
||||
|
@ -1241,15 +1183,10 @@ void
|
|||
TrackBuffersManager::DoDemuxAudio()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
|
||||
if (!HasAudio()) {
|
||||
CompleteCodedFrameProcessing();
|
||||
return;
|
||||
}
|
||||
if (mAbort) {
|
||||
RejectProcessing(NS_ERROR_ABORT, __func__);
|
||||
return;
|
||||
}
|
||||
mAudioTracks.mDemuxRequest.Begin(mAudioTracks.mDemuxer->GetSamples(-1)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&TrackBuffersManager::OnAudioDemuxCompleted,
|
||||
|
@ -1270,7 +1207,6 @@ void
|
|||
TrackBuffersManager::CompleteCodedFrameProcessing()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
|
||||
|
||||
// 1. For each coded frame in the media segment run the following steps:
|
||||
// Coded Frame Processing steps 1.1 to 1.21.
|
||||
|
@ -1341,22 +1277,12 @@ TrackBuffersManager::CompleteCodedFrameProcessing()
|
|||
void
|
||||
TrackBuffersManager::RejectProcessing(nsresult aRejectValue, const char* aName)
|
||||
{
|
||||
if (mAbort) {
|
||||
// mAppendPromise will be resolved immediately upon mProcessingPromise
|
||||
// completing.
|
||||
mAppendRunning = false;
|
||||
}
|
||||
mProcessingPromise.RejectIfExists(aRejectValue, __func__);
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffersManager::ResolveProcessing(bool aResolveValue, const char* aName)
|
||||
{
|
||||
if (mAbort) {
|
||||
// mAppendPromise will be resolved immediately upon mProcessingPromise
|
||||
// completing.
|
||||
mAppendRunning = false;
|
||||
}
|
||||
mProcessingPromise.ResolveIfExists(aResolveValue, __func__);
|
||||
}
|
||||
|
||||
|
|
|
@ -98,10 +98,6 @@ public:
|
|||
bool& aError);
|
||||
media::TimeUnit GetNextRandomAccessPoint(TrackInfo::TrackType aTrack);
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Dump(const char* aPath) override;
|
||||
#endif
|
||||
|
||||
void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes);
|
||||
|
||||
private:
|
||||
|
@ -123,9 +119,7 @@ private:
|
|||
// media segment have been processed.
|
||||
RefPtr<CodedFrameProcessingPromise> CodedFrameProcessing();
|
||||
void CompleteCodedFrameProcessing();
|
||||
// Called by ResetParserState. Complete parsing the input buffer for the
|
||||
// current media segment.
|
||||
void FinishCodedFrameProcessing();
|
||||
// Called by ResetParserState.
|
||||
void CompleteResetParserState();
|
||||
RefPtr<RangeRemovalPromise>
|
||||
CodedFrameRemovalWithPromise(media::TimeInterval aInterval);
|
||||
|
@ -310,10 +304,6 @@ private:
|
|||
MozPromiseHolder<CodedFrameProcessingPromise> mProcessingPromise;
|
||||
|
||||
MozPromiseHolder<AppendPromise> mAppendPromise;
|
||||
// Set to true while SegmentParserLoop is running. This is used for diagnostic
|
||||
// purposes only. We can't rely on mAppendPromise to be empty as it is only
|
||||
// cleared in a follow up task.
|
||||
bool mAppendRunning;
|
||||
|
||||
// Trackbuffers definition.
|
||||
nsTArray<TrackData*> GetTracksList();
|
||||
|
@ -349,11 +339,6 @@ private:
|
|||
RefPtr<dom::SourceBufferAttributes> mSourceBufferAttributes;
|
||||
nsMainThreadPtrHandle<MediaSourceDecoder> mParentDecoder;
|
||||
|
||||
// MediaSource duration mirrored from MediaDecoder on the main thread..
|
||||
Mirror<Maybe<double>> mMediaSourceDuration;
|
||||
|
||||
// Set to true if abort was called.
|
||||
Atomic<bool> mAbort;
|
||||
// Set to true if mediasource state changed to ended.
|
||||
Atomic<bool> mEnded;
|
||||
|
||||
|
@ -363,7 +348,13 @@ private:
|
|||
Atomic<bool> mEvictionOccurred;
|
||||
|
||||
// Monitor to protect following objects accessed across multipple threads.
|
||||
// mMonitor is also notified if the value of mAppendRunning becomes false.
|
||||
mutable Monitor mMonitor;
|
||||
// Set to true while SegmentParserLoop is running.
|
||||
Atomic<bool> mAppendRunning;
|
||||
// Set to true while SegmentParserLoop is running.
|
||||
// This is for diagnostic only. Only accessed on the task queue.
|
||||
bool mSegmentParserLoopRunning;
|
||||
// Stable audio and video track time ranges.
|
||||
media::TimeIntervals mVideoBufferedRanges;
|
||||
media::TimeIntervals mAudioBufferedRanges;
|
||||
|
|
|
@ -52,10 +52,7 @@ dictionary ConsoleEvent {
|
|||
DOMString functionName = "";
|
||||
double timeStamp = 0;
|
||||
sequence<any> arguments;
|
||||
|
||||
// This array will only hold strings or null elements.
|
||||
sequence<any> styles;
|
||||
|
||||
sequence<DOMString?> styles;
|
||||
boolean private = false;
|
||||
// stacktrace is handled via a getter in some cases so we can construct it
|
||||
// lazily. Note that we're not making this whole thing an interface because
|
||||
|
|
|
@ -190,7 +190,7 @@ Navigator implements NavigatorMobileId;
|
|||
|
||||
// nsIDOMNavigator
|
||||
partial interface Navigator {
|
||||
[Throws]
|
||||
[Throws, Constant, Cached]
|
||||
readonly attribute DOMString oscpu;
|
||||
// WebKit/Blink support this; Trident/Presto do not.
|
||||
readonly attribute DOMString vendor;
|
||||
|
@ -200,7 +200,7 @@ partial interface Navigator {
|
|||
readonly attribute DOMString productSub;
|
||||
// WebKit/Blink/Trident/Presto support this.
|
||||
readonly attribute boolean cookieEnabled;
|
||||
[Throws]
|
||||
[Throws, Constant, Cached]
|
||||
readonly attribute DOMString buildID;
|
||||
[Throws, CheckAnyPermissions="power", UnsafeInPrerendering]
|
||||
readonly attribute MozPowerManager mozPower;
|
||||
|
|
|
@ -2391,6 +2391,7 @@ nsWebBrowserPersist::FixRedirectedChannelEntry(nsIChannel *aNewChannel)
|
|||
// matching the one specified.
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
aNewChannel->GetOriginalURI(getter_AddRefs(originalURI));
|
||||
nsISupports* matchingKey = nullptr;
|
||||
for (auto iter = mOutputMap.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsISupports* key = iter.Key();
|
||||
nsCOMPtr<nsIChannel> thisChannel = do_QueryInterface(key);
|
||||
|
@ -2402,21 +2403,25 @@ nsWebBrowserPersist::FixRedirectedChannelEntry(nsIChannel *aNewChannel)
|
|||
bool matchingURI = false;
|
||||
thisURI->Equals(originalURI, &matchingURI);
|
||||
if (matchingURI) {
|
||||
// If a match is found, remove the data entry with the old channel
|
||||
// key and re-add it with the new channel key.
|
||||
nsAutoPtr<OutputData> outputData;
|
||||
mOutputMap.RemoveAndForget(key, outputData);
|
||||
NS_ENSURE_TRUE(outputData, NS_ERROR_FAILURE);
|
||||
|
||||
// Store data again with new channel unless told to ignore redirects
|
||||
if (!(mPersistFlags & PERSIST_FLAGS_IGNORE_REDIRECTED_DATA)) {
|
||||
nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(aNewChannel);
|
||||
mOutputMap.Put(keyPtr, outputData.forget());
|
||||
}
|
||||
|
||||
matchingKey = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingKey) {
|
||||
// If a match was found, remove the data entry with the old channel
|
||||
// key and re-add it with the new channel key.
|
||||
nsAutoPtr<OutputData> outputData;
|
||||
mOutputMap.RemoveAndForget(matchingKey, outputData);
|
||||
NS_ENSURE_TRUE(outputData, NS_ERROR_FAILURE);
|
||||
|
||||
// Store data again with new channel unless told to ignore redirects.
|
||||
if (!(mPersistFlags & PERSIST_FLAGS_IGNORE_REDIRECTED_DATA)) {
|
||||
nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(aNewChannel);
|
||||
mOutputMap.Put(keyPtr, outputData.forget());
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
11
gfx/2d/2D.h
11
gfx/2d/2D.h
|
@ -36,8 +36,6 @@ typedef _cairo_surface cairo_surface_t;
|
|||
struct _cairo_scaled_font;
|
||||
typedef _cairo_scaled_font cairo_scaled_font_t;
|
||||
|
||||
struct ID3D10Device1;
|
||||
struct ID3D10Texture2D;
|
||||
struct ID3D11Texture2D;
|
||||
struct ID3D11Device;
|
||||
struct ID2D1Device;
|
||||
|
@ -1364,14 +1362,6 @@ public:
|
|||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
static already_AddRefed<DrawTarget> CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat);
|
||||
static already_AddRefed<DrawTarget>
|
||||
CreateDualDrawTargetForD3D10Textures(ID3D10Texture2D *aTextureA,
|
||||
ID3D10Texture2D *aTextureB,
|
||||
SurfaceFormat aFormat);
|
||||
|
||||
static void SetDirect3D10Device(ID3D10Device1 *aDevice);
|
||||
static ID3D10Device1 *GetDirect3D10Device();
|
||||
static already_AddRefed<DrawTarget> CreateDrawTargetForD3D11Texture(ID3D11Texture2D *aTexture, SurfaceFormat aFormat);
|
||||
|
||||
static void SetDirect3D11Device(ID3D11Device *aDevice);
|
||||
|
@ -1394,7 +1384,6 @@ public:
|
|||
|
||||
private:
|
||||
static ID2D1Device *mD2D1Device;
|
||||
static ID3D10Device1 *mD3D10Device;
|
||||
static ID3D11Device *mD3D11Device;
|
||||
#endif
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,290 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_DRAWTARGETD2D_H_
|
||||
#define MOZILLA_GFX_DRAWTARGETD2D_H_
|
||||
|
||||
#include "2D.h"
|
||||
#include "PathD2D.h"
|
||||
#include <d3d10_1.h>
|
||||
#include "HelpersD2D.h"
|
||||
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
struct IDWriteFactory;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
class SourceSurfaceD2DTarget;
|
||||
class SourceSurfaceD2D;
|
||||
class GradientStopsD2D;
|
||||
class ScaledFontDWrite;
|
||||
|
||||
const int32_t kLayerCacheSize = 5;
|
||||
|
||||
struct PrivateD3D10DataD2D
|
||||
{
|
||||
RefPtr<ID3D10Effect> mEffect;
|
||||
RefPtr<ID3D10InputLayout> mInputLayout;
|
||||
RefPtr<ID3D10Buffer> mVB;
|
||||
RefPtr<ID3D10BlendState> mBlendStates[size_t(CompositionOp::OP_COUNT)];
|
||||
};
|
||||
|
||||
class DrawTargetD2D : public DrawTarget
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetD2D, override)
|
||||
DrawTargetD2D();
|
||||
virtual ~DrawTargetD2D();
|
||||
|
||||
virtual DrawTargetType GetType() const override { return DrawTargetType::HARDWARE_RASTER; }
|
||||
virtual BackendType GetBackendType() const override { return BackendType::DIRECT2D; }
|
||||
virtual already_AddRefed<SourceSurface> Snapshot() override;
|
||||
virtual IntSize GetSize() override { return mSize; }
|
||||
|
||||
virtual void Flush() override;
|
||||
virtual void DrawSurface(SourceSurface *aSurface,
|
||||
const Rect &aDest,
|
||||
const Rect &aSource,
|
||||
const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
|
||||
const DrawOptions &aOptions = DrawOptions()) override;
|
||||
virtual void DrawFilter(FilterNode *aNode,
|
||||
const Rect &aSourceRect,
|
||||
const Point &aDestPoint,
|
||||
const DrawOptions &aOptions = DrawOptions()) override;
|
||||
virtual void DrawSurfaceWithShadow(SourceSurface *aSurface,
|
||||
const Point &aDest,
|
||||
const Color &aColor,
|
||||
const Point &aOffset,
|
||||
Float aSigma,
|
||||
CompositionOp aOperator) override;
|
||||
virtual void ClearRect(const Rect &aRect) override;
|
||||
virtual void MaskSurface(const Pattern &aSource,
|
||||
SourceSurface *aMask,
|
||||
Point aOffset,
|
||||
const DrawOptions &aOptions = DrawOptions()) override;
|
||||
|
||||
|
||||
virtual void CopySurface(SourceSurface *aSurface,
|
||||
const IntRect &aSourceRect,
|
||||
const IntPoint &aDestination) override;
|
||||
|
||||
virtual void FillRect(const Rect &aRect,
|
||||
const Pattern &aPattern,
|
||||
const DrawOptions &aOptions = DrawOptions()) override;
|
||||
virtual void StrokeRect(const Rect &aRect,
|
||||
const Pattern &aPattern,
|
||||
const StrokeOptions &aStrokeOptions = StrokeOptions(),
|
||||
const DrawOptions &aOptions = DrawOptions()) override;
|
||||
virtual void StrokeLine(const Point &aStart,
|
||||
const Point &aEnd,
|
||||
const Pattern &aPattern,
|
||||
const StrokeOptions &aStrokeOptions = StrokeOptions(),
|
||||
const DrawOptions &aOptions = DrawOptions()) override;
|
||||
virtual void Stroke(const Path *aPath,
|
||||
const Pattern &aPattern,
|
||||
const StrokeOptions &aStrokeOptions = StrokeOptions(),
|
||||
const DrawOptions &aOptions = DrawOptions()) override;
|
||||
virtual void Fill(const Path *aPath,
|
||||
const Pattern &aPattern,
|
||||
const DrawOptions &aOptions = DrawOptions()) override;
|
||||
virtual void FillGlyphs(ScaledFont *aFont,
|
||||
const GlyphBuffer &aBuffer,
|
||||
const Pattern &aPattern,
|
||||
const DrawOptions &aOptions = DrawOptions(),
|
||||
const GlyphRenderingOptions *aRenderingOptions = nullptr) override;
|
||||
virtual void Mask(const Pattern &aSource,
|
||||
const Pattern &aMask,
|
||||
const DrawOptions &aOptions = DrawOptions()) override;
|
||||
virtual void PushClip(const Path *aPath) override;
|
||||
virtual void PushClipRect(const Rect &aRect) override;
|
||||
virtual void PopClip() override;
|
||||
|
||||
virtual already_AddRefed<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
|
||||
const IntSize &aSize,
|
||||
int32_t aStride,
|
||||
SurfaceFormat aFormat) const override;
|
||||
virtual already_AddRefed<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const override;
|
||||
|
||||
virtual already_AddRefed<SourceSurface>
|
||||
CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const override;
|
||||
|
||||
virtual already_AddRefed<DrawTarget>
|
||||
CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const override;
|
||||
|
||||
virtual already_AddRefed<PathBuilder> CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const override;
|
||||
|
||||
virtual already_AddRefed<GradientStops>
|
||||
CreateGradientStops(GradientStop *aStops,
|
||||
uint32_t aNumStops,
|
||||
ExtendMode aExtendMode = ExtendMode::CLAMP) const override;
|
||||
|
||||
virtual already_AddRefed<FilterNode> CreateFilter(FilterType aType) override;
|
||||
|
||||
virtual bool SupportsRegionClipping() const override { return false; }
|
||||
|
||||
virtual void *GetNativeSurface(NativeSurfaceType aType) override;
|
||||
|
||||
bool Init(const IntSize &aSize, SurfaceFormat aFormat);
|
||||
bool Init(ID3D10Texture2D *aTexture, SurfaceFormat aFormat);
|
||||
bool InitD3D10Data();
|
||||
uint32_t GetByteSize() const;
|
||||
already_AddRefed<ID2D1Layer> GetCachedLayer();
|
||||
void PopCachedLayer(ID2D1RenderTarget *aRT);
|
||||
|
||||
already_AddRefed<ID2D1Image> GetImageForSurface(SourceSurface *aSurface);
|
||||
|
||||
static ID2D1Factory *factory();
|
||||
static void CleanupD2D();
|
||||
static IDWriteFactory *GetDWriteFactory();
|
||||
ID2D1RenderTarget *GetRT() { return mRT; }
|
||||
|
||||
static uint32_t GetMaxSurfaceSize() {
|
||||
return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
}
|
||||
|
||||
operator std::string() const {
|
||||
std::stringstream stream;
|
||||
stream << "DrawTargetD2D(" << this << ")";
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
static uint64_t mVRAMUsageDT;
|
||||
static uint64_t mVRAMUsageSS;
|
||||
|
||||
private:
|
||||
already_AddRefed<ID2D1Bitmap>
|
||||
GetBitmapForSurface(SourceSurface *aSurface,
|
||||
Rect &aSource);
|
||||
friend class AutoSaveRestoreClippedOut;
|
||||
friend class SourceSurfaceD2DTarget;
|
||||
|
||||
typedef std::unordered_set<DrawTargetD2D*> TargetSet;
|
||||
|
||||
bool InitD2DRenderTarget();
|
||||
void PrepareForDrawing(ID2D1RenderTarget *aRT);
|
||||
|
||||
// This function will mark the surface as changing, and make sure any
|
||||
// copy-on-write snapshots are notified.
|
||||
void MarkChanged();
|
||||
void FlushTransformToRT() {
|
||||
if (mTransformDirty) {
|
||||
mRT->SetTransform(D2DMatrix(mTransform));
|
||||
mTransformDirty = false;
|
||||
}
|
||||
}
|
||||
void AddDependencyOnSource(SourceSurfaceD2DTarget* aSource);
|
||||
|
||||
ID3D10BlendState *GetBlendStateForOperator(CompositionOp aOperator);
|
||||
ID2D1RenderTarget *GetRTForOperation(CompositionOp aOperator, const Pattern &aPattern);
|
||||
void FinalizeRTForOperation(CompositionOp aOperator, const Pattern &aPattern, const Rect &aBounds); void EnsureViews();
|
||||
void PopAllClips();
|
||||
void PushClipsToRT(ID2D1RenderTarget *aRT);
|
||||
void PopClipsFromRT(ID2D1RenderTarget *aRT);
|
||||
|
||||
// This function ensures mCurrentClipMaskTexture contains a texture containing
|
||||
// a mask corresponding with the current DrawTarget clip. See
|
||||
// GetClippedGeometry for a description of aClipBounds.
|
||||
void EnsureClipMaskTexture(IntRect *aClipBounds);
|
||||
|
||||
bool FillGlyphsManual(ScaledFontDWrite *aFont,
|
||||
const GlyphBuffer &aBuffer,
|
||||
const Color &aColor,
|
||||
IDWriteRenderingParams *aParams,
|
||||
const DrawOptions &aOptions = DrawOptions());
|
||||
|
||||
already_AddRefed<ID2D1RenderTarget> CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat);
|
||||
|
||||
// This returns the clipped geometry, in addition it returns aClipBounds which
|
||||
// represents the intersection of all pixel-aligned rectangular clips that
|
||||
// are currently set. The returned clipped geometry must be clipped by these
|
||||
// bounds to correctly reflect the total clip. This is in device space.
|
||||
already_AddRefed<ID2D1Geometry> GetClippedGeometry(IntRect *aClipBounds);
|
||||
|
||||
bool GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned);
|
||||
|
||||
already_AddRefed<ID2D1Brush> CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f);
|
||||
|
||||
already_AddRefed<ID3D10Texture2D> CreateGradientTexture(const GradientStopsD2D *aStops);
|
||||
already_AddRefed<ID3D10Texture2D> CreateTextureForAnalysis(IDWriteGlyphRunAnalysis *aAnalysis, const IntRect &aBounds);
|
||||
|
||||
void SetupEffectForRadialGradient(const RadialGradientPattern *aPattern);
|
||||
void SetupStateForRendering();
|
||||
|
||||
// Set the scissor rect to a certain IntRects, resets the scissor rect to
|
||||
// surface bounds when nullptr is specified.
|
||||
void SetScissorToRect(IntRect *aRect);
|
||||
|
||||
void PushD2DLayer(ID2D1RenderTarget *aRT, ID2D1Geometry *aGeometry, ID2D1Layer *aLayer, const D2D1_MATRIX_3X2_F &aTransform);
|
||||
|
||||
static const uint32_t test = 4;
|
||||
|
||||
IntSize mSize;
|
||||
|
||||
RefPtr<ID3D10Device1> mDevice;
|
||||
RefPtr<ID3D10Texture2D> mTexture;
|
||||
RefPtr<ID3D10Texture2D> mCurrentClipMaskTexture;
|
||||
RefPtr<ID2D1Geometry> mCurrentClippedGeometry;
|
||||
// This is only valid if mCurrentClippedGeometry is non-null. And will
|
||||
// only be the intersection of all pixel-aligned retangular clips. This is in
|
||||
// device space.
|
||||
IntRect mCurrentClipBounds;
|
||||
mutable RefPtr<ID2D1RenderTarget> mRT;
|
||||
|
||||
// We store this to prevent excessive SetTextRenderingParams calls.
|
||||
RefPtr<IDWriteRenderingParams> mTextRenderingParams;
|
||||
|
||||
// Temporary texture and render target used for supporting alternative operators.
|
||||
RefPtr<ID3D10Texture2D> mTempTexture;
|
||||
RefPtr<ID3D10RenderTargetView> mRTView;
|
||||
RefPtr<ID3D10ShaderResourceView> mSRView;
|
||||
RefPtr<ID2D1RenderTarget> mTempRT;
|
||||
RefPtr<ID3D10RenderTargetView> mTempRTView;
|
||||
|
||||
// List of pushed clips.
|
||||
struct PushedClip
|
||||
{
|
||||
RefPtr<ID2D1Layer> mLayer;
|
||||
D2D1_RECT_F mBounds;
|
||||
union {
|
||||
// If mPath is non-nullptr, the mTransform member will be used, otherwise
|
||||
// the mIsPixelAligned member is valid.
|
||||
D2D1_MATRIX_3X2_F mTransform;
|
||||
bool mIsPixelAligned;
|
||||
};
|
||||
RefPtr<PathD2D> mPath;
|
||||
};
|
||||
std::vector<PushedClip> mPushedClips;
|
||||
|
||||
// We cache ID2D1Layer objects as it causes D2D to keep around textures that
|
||||
// serve as the temporary surfaces for these operations. As texture creation
|
||||
// is quite expensive this considerably improved performance.
|
||||
// Careful here, RAII will not ensure destruction of the RefPtrs.
|
||||
RefPtr<ID2D1Layer> mCachedLayers[kLayerCacheSize];
|
||||
uint32_t mCurrentCachedLayer;
|
||||
|
||||
// The latest snapshot of this surface. This needs to be told when this
|
||||
// target is modified. We keep it alive as a cache.
|
||||
RefPtr<SourceSurfaceD2DTarget> mSnapshot;
|
||||
// A list of targets we need to flush when we're modified.
|
||||
TargetSet mDependentTargets;
|
||||
// A list of targets which have this object in their mDependentTargets set
|
||||
TargetSet mDependingOnTargets;
|
||||
|
||||
// True of the current clip stack is pushed to the main RT.
|
||||
bool mClipsArePushed;
|
||||
PrivateD3D10DataD2D *mPrivateData;
|
||||
static ID2D1Factory *mFactory;
|
||||
static IDWriteFactory *mDWriteFactory;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MOZILLA_GFX_DRAWTARGETD2D_H_ */
|
|
@ -5,24 +5,32 @@
|
|||
|
||||
#include <initguid.h>
|
||||
#include "DrawTargetD2D1.h"
|
||||
#include "DrawTargetD2D.h"
|
||||
#include "FilterNodeSoftware.h"
|
||||
#include "GradientStopsD2D.h"
|
||||
#include "SourceSurfaceD2D1.h"
|
||||
#include "SourceSurfaceD2D.h"
|
||||
#include "RadialGradientEffectD2D1.h"
|
||||
|
||||
#include "HelpersD2D.h"
|
||||
#include "FilterNodeD2D1.h"
|
||||
#include "ExtendInputEffectD2D1.h"
|
||||
#include "Tools.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// decltype is not usable for overloaded functions.
|
||||
typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
|
||||
D2D1_FACTORY_TYPE factoryType,
|
||||
REFIID iid,
|
||||
CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
|
||||
void **factory
|
||||
);
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
uint64_t DrawTargetD2D1::mVRAMUsageDT;
|
||||
uint64_t DrawTargetD2D1::mVRAMUsageSS;
|
||||
IDWriteFactory *DrawTargetD2D1::mDWriteFactory;
|
||||
ID2D1Factory1* DrawTargetD2D1::mFactory = nullptr;
|
||||
|
||||
ID2D1Factory1 *D2DFactory1()
|
||||
|
@ -604,7 +612,7 @@ DrawTargetD2D1::FillGlyphs(ScaledFont *aFont,
|
|||
DWRITE_MEASURING_MODE_NATURAL, &userRect);
|
||||
|
||||
RefPtr<ID2D1PathGeometry> path;
|
||||
D2DFactory()->CreatePathGeometry(getter_AddRefs(path));
|
||||
factory()->CreatePathGeometry(getter_AddRefs(path));
|
||||
RefPtr<ID2D1GeometrySink> sink;
|
||||
path->Open(getter_AddRefs(sink));
|
||||
AddRectToSink(sink, userRect);
|
||||
|
@ -1060,27 +1068,79 @@ DrawTargetD2D1::factory()
|
|||
return mFactory;
|
||||
}
|
||||
|
||||
ID2D1Factory* d2dFactory = D2DFactory();
|
||||
if (!d2dFactory) {
|
||||
RefPtr<ID2D1Factory> factory;
|
||||
D2D1CreateFactoryFunc createD2DFactory;
|
||||
HMODULE d2dModule = LoadLibraryW(L"d2d1.dll");
|
||||
createD2DFactory = (D2D1CreateFactoryFunc)
|
||||
GetProcAddress(d2dModule, "D2D1CreateFactory");
|
||||
|
||||
if (!createD2DFactory) {
|
||||
gfxWarning() << "Failed to locate D2D1CreateFactory function.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HRESULT hr = d2dFactory->QueryInterface((ID2D1Factory1**)&mFactory);
|
||||
D2D1_FACTORY_OPTIONS options;
|
||||
#ifdef _DEBUG
|
||||
options.debugLevel = D2D1_DEBUG_LEVEL_WARNING;
|
||||
#else
|
||||
options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
|
||||
#endif
|
||||
//options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
|
||||
|
||||
if (FAILED(hr)) {
|
||||
HRESULT hr = createD2DFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,
|
||||
__uuidof(ID2D1Factory),
|
||||
&options,
|
||||
getter_AddRefs(factory));
|
||||
|
||||
if (FAILED(hr) || !factory) {
|
||||
gfxWarning() << "Failed to create Direct2D factory.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hr = factory->QueryInterface((ID2D1Factory1**)&mFactory);
|
||||
if (FAILED(hr) || !mFactory) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ExtendInputEffectD2D1::Register(mFactory);
|
||||
RadialGradientEffectD2D1::Register(mFactory);
|
||||
|
||||
return mFactory;
|
||||
}
|
||||
|
||||
IDWriteFactory*
|
||||
DrawTargetD2D1::GetDWriteFactory()
|
||||
{
|
||||
if (mDWriteFactory) {
|
||||
return mDWriteFactory;
|
||||
}
|
||||
|
||||
decltype(DWriteCreateFactory)* createDWriteFactory;
|
||||
HMODULE dwriteModule = LoadLibraryW(L"dwrite.dll");
|
||||
createDWriteFactory = (decltype(DWriteCreateFactory)*)
|
||||
GetProcAddress(dwriteModule, "DWriteCreateFactory");
|
||||
|
||||
if (!createDWriteFactory) {
|
||||
gfxWarning() << "Failed to locate DWriteCreateFactory function.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HRESULT hr = createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
|
||||
reinterpret_cast<IUnknown**>(&mDWriteFactory));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to create DWrite Factory.";
|
||||
}
|
||||
|
||||
return mDWriteFactory;
|
||||
}
|
||||
|
||||
void
|
||||
DrawTargetD2D1::CleanupD2D()
|
||||
{
|
||||
if (mFactory) {
|
||||
RadialGradientEffectD2D1::Unregister(mFactory);
|
||||
ExtendInputEffectD2D1::Unregister(mFactory);
|
||||
mFactory->Release();
|
||||
mFactory = nullptr;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "DrawTargetD2D.h"
|
||||
#include "DrawTargetD2D1.h"
|
||||
#include "ScaledFontDWrite.h"
|
||||
#include "NativeFontResourceDWrite.h"
|
||||
|
@ -161,7 +160,6 @@ int32_t LoggingPrefs::sGfxLogLevel =
|
|||
LOG_DEFAULT);
|
||||
|
||||
#ifdef WIN32
|
||||
ID3D10Device1 *Factory::mD3D10Device;
|
||||
ID3D11Device *Factory::mD3D11Device;
|
||||
ID2D1Device *Factory::mD2D1Device;
|
||||
#endif
|
||||
|
@ -315,15 +313,6 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor
|
|||
RefPtr<DrawTarget> retVal;
|
||||
switch (aBackend) {
|
||||
#ifdef WIN32
|
||||
case BackendType::DIRECT2D:
|
||||
{
|
||||
RefPtr<DrawTargetD2D> newTarget;
|
||||
newTarget = new DrawTargetD2D();
|
||||
if (newTarget->Init(aSize, aFormat)) {
|
||||
retVal = newTarget;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BackendType::DIRECT2D1_1:
|
||||
{
|
||||
RefPtr<DrawTargetD2D1> newTarget;
|
||||
|
@ -499,8 +488,6 @@ Factory::GetMaxSurfaceSize(BackendType aType)
|
|||
return DrawTargetSkia::GetMaxSurfaceSize();
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
case BackendType::DIRECT2D:
|
||||
return DrawTargetD2D::GetMaxSurfaceSize();
|
||||
case BackendType::DIRECT2D1_1:
|
||||
return DrawTargetD2D1::GetMaxSurfaceSize();
|
||||
#endif
|
||||
|
@ -611,87 +598,6 @@ Factory::CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB)
|
|||
|
||||
|
||||
#ifdef WIN32
|
||||
already_AddRefed<DrawTarget>
|
||||
Factory::CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat)
|
||||
{
|
||||
MOZ_ASSERT(aTexture);
|
||||
|
||||
RefPtr<DrawTargetD2D> newTarget;
|
||||
|
||||
newTarget = new DrawTargetD2D();
|
||||
if (newTarget->Init(aTexture, aFormat)) {
|
||||
RefPtr<DrawTarget> retVal = newTarget;
|
||||
|
||||
if (mRecorder) {
|
||||
retVal = new DrawTargetRecording(mRecorder, retVal, true);
|
||||
}
|
||||
|
||||
return retVal.forget();
|
||||
}
|
||||
|
||||
gfxWarning() << "Failed to create draw target for D3D10 texture.";
|
||||
|
||||
// Failed
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<DrawTarget>
|
||||
Factory::CreateDualDrawTargetForD3D10Textures(ID3D10Texture2D *aTextureA,
|
||||
ID3D10Texture2D *aTextureB,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
MOZ_ASSERT(aTextureA && aTextureB);
|
||||
RefPtr<DrawTargetD2D> newTargetA;
|
||||
RefPtr<DrawTargetD2D> newTargetB;
|
||||
|
||||
newTargetA = new DrawTargetD2D();
|
||||
if (!newTargetA->Init(aTextureA, aFormat)) {
|
||||
gfxWarning() << "Failed to create dual draw target for D3D10 texture.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
newTargetB = new DrawTargetD2D();
|
||||
if (!newTargetB->Init(aTextureB, aFormat)) {
|
||||
gfxWarning() << "Failed to create new draw target for D3D10 texture.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> newTarget =
|
||||
new DrawTargetDual(newTargetA, newTargetB);
|
||||
|
||||
RefPtr<DrawTarget> retVal = newTarget;
|
||||
|
||||
if (mRecorder) {
|
||||
retVal = new DrawTargetRecording(mRecorder, retVal);
|
||||
}
|
||||
|
||||
return retVal.forget();
|
||||
}
|
||||
|
||||
void
|
||||
Factory::SetDirect3D10Device(ID3D10Device1 *aDevice)
|
||||
{
|
||||
// do not throw on failure; return error codes and disconnect the device
|
||||
// On Windows 8 error codes are the default, but on Windows 7 the
|
||||
// default is to throw (or perhaps only with some drivers?)
|
||||
if (aDevice) {
|
||||
aDevice->SetExceptionMode(0);
|
||||
}
|
||||
mD3D10Device = aDevice;
|
||||
}
|
||||
|
||||
ID3D10Device1*
|
||||
Factory::GetDirect3D10Device()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (mD3D10Device) {
|
||||
UINT mode = mD3D10Device->GetExceptionMode();
|
||||
MOZ_ASSERT(0 == mode);
|
||||
}
|
||||
#endif
|
||||
return mD3D10Device;
|
||||
}
|
||||
|
||||
already_AddRefed<DrawTarget>
|
||||
Factory::CreateDrawTargetForD3D11Texture(ID3D11Texture2D *aTexture, SurfaceFormat aFormat)
|
||||
{
|
||||
|
@ -767,13 +673,13 @@ Factory::CreateDWriteGlyphRenderingOptions(IDWriteRenderingParams *aParams)
|
|||
uint64_t
|
||||
Factory::GetD2DVRAMUsageDrawTarget()
|
||||
{
|
||||
return DrawTargetD2D::mVRAMUsageDT;
|
||||
return DrawTargetD2D1::mVRAMUsageDT;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Factory::GetD2DVRAMUsageSourceSurface()
|
||||
{
|
||||
return DrawTargetD2D::mVRAMUsageSS;
|
||||
return DrawTargetD2D1::mVRAMUsageSS;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -784,7 +690,6 @@ Factory::D2DCleanup()
|
|||
mD2D1Device = nullptr;
|
||||
}
|
||||
DrawTargetD2D1::CleanupD2D();
|
||||
DrawTargetD2D::CleanupD2D();
|
||||
}
|
||||
|
||||
already_AddRefed<ScaledFont>
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
#include "Logging.h"
|
||||
|
||||
#include "SourceSurfaceD2D1.h"
|
||||
#include "SourceSurfaceD2D.h"
|
||||
#include "SourceSurfaceD2DTarget.h"
|
||||
#include "DrawTargetD2D.h"
|
||||
#include "DrawTargetD2D1.h"
|
||||
#include "ExtendInputEffectD2D1.h"
|
||||
|
||||
|
@ -159,8 +156,6 @@ already_AddRefed<ID2D1Image> GetImageForSourceSurface(DrawTarget *aDT, SourceSur
|
|||
switch (aDT->GetBackendType()) {
|
||||
case BackendType::DIRECT2D1_1:
|
||||
return static_cast<DrawTargetD2D1*>(aDT)->GetImageForSurface(aSurface, ExtendMode::CLAMP);
|
||||
case BackendType::DIRECT2D:
|
||||
return static_cast<DrawTargetD2D*>(aDT)->GetImageForSurface(aSurface);
|
||||
default:
|
||||
gfxDevCrash(LogReason::FilterNodeD2D1Backend) << "Unknown draw target type! " << (int)aDT->GetBackendType();
|
||||
return nullptr;
|
||||
|
|
|
@ -25,9 +25,8 @@
|
|||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
ID2D1Factory* D2DFactory();
|
||||
|
||||
ID2D1Factory1* D2DFactory1();
|
||||
static ID2D1Factory* D2DFactory() { return D2DFactory1(); }
|
||||
|
||||
static inline D2D1_POINT_2F D2DPoint(const Point &aPoint)
|
||||
{
|
||||
|
|
|
@ -96,8 +96,7 @@ public:
|
|||
/// In the event of a crash, the crash report is annotated with first and
|
||||
/// the last few of these errors, under the key GraphicsCriticalError.
|
||||
/// The total number of errors stored in the crash report is controlled
|
||||
/// by preference gfx.logging.crash.length (default is six, so by default,
|
||||
/// the first as well as the last five would show up in the crash log.)
|
||||
/// by preference gfx.logging.crash.length.
|
||||
///
|
||||
/// On platforms that support MOZ_LOGGING, the story is slightly more involved.
|
||||
/// In that case, unless gfx.logging.level is set to 4 or higher, the output
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "DrawTargetD2D.h"
|
||||
#include "DrawTargetD2D1.h"
|
||||
#include "Logging.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
|
@ -69,7 +69,7 @@ public:
|
|||
{
|
||||
if (!mInstance) {
|
||||
mInstance = new DWriteFontFileLoader();
|
||||
DrawTargetD2D::GetDWriteFactory()->
|
||||
DrawTargetD2D1::GetDWriteFactory()->
|
||||
RegisterFontFileLoader(mInstance);
|
||||
}
|
||||
return mInstance;
|
||||
|
@ -221,7 +221,7 @@ already_AddRefed<NativeFontResourceDWrite>
|
|||
NativeFontResourceDWrite::Create(uint8_t *aFontData, uint32_t aDataLength,
|
||||
bool aNeedsCairo)
|
||||
{
|
||||
IDWriteFactory *factory = DrawTargetD2D::GetDWriteFactory();
|
||||
IDWriteFactory *factory = DrawTargetD2D1::GetDWriteFactory();
|
||||
if (!factory) {
|
||||
gfxWarning() << "Failed to get DWrite Factory.";
|
||||
return nullptr;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "PathD2D.h"
|
||||
#include "HelpersD2D.h"
|
||||
#include <math.h>
|
||||
#include "DrawTargetD2D.h"
|
||||
#include "DrawTargetD2D1.h"
|
||||
#include "Logging.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -351,7 +351,7 @@ already_AddRefed<PathBuilder>
|
|||
PathD2D::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
|
||||
{
|
||||
RefPtr<ID2D1PathGeometry> path;
|
||||
HRESULT hr = DrawTargetD2D::factory()->CreatePathGeometry(getter_AddRefs(path));
|
||||
HRESULT hr = DrawTargetD2D1::factory()->CreatePathGeometry(getter_AddRefs(path));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to create PathGeometry. Code: " << hexa(hr);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DrawTargetD2D.h"
|
||||
#include "DrawTargetD2D1.h"
|
||||
#include "ScaledFontDWrite.h"
|
||||
#include "PathD2D.h"
|
||||
|
||||
|
@ -120,7 +120,7 @@ ScaledFontDWrite::GetSkTypeface()
|
|||
{
|
||||
MOZ_ASSERT(mFont);
|
||||
if (!mTypeface) {
|
||||
IDWriteFactory *factory = DrawTargetD2D::GetDWriteFactory();
|
||||
IDWriteFactory *factory = DrawTargetD2D1::GetDWriteFactory();
|
||||
mTypeface = SkCreateTypefaceFromDWriteFont(factory, mFontFace, mFont, mFontFamily);
|
||||
}
|
||||
return mTypeface;
|
||||
|
|
|
@ -1,317 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SourceSurfaceD2D.h"
|
||||
#include "DrawTargetD2D.h"
|
||||
#include "Logging.h"
|
||||
#include "Tools.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
SourceSurfaceD2D::SourceSurfaceD2D()
|
||||
{
|
||||
}
|
||||
|
||||
SourceSurfaceD2D::~SourceSurfaceD2D()
|
||||
{
|
||||
if (mBitmap) {
|
||||
DrawTargetD2D::mVRAMUsageSS -= GetByteSize();
|
||||
}
|
||||
}
|
||||
|
||||
IntSize
|
||||
SourceSurfaceD2D::GetSize() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
SurfaceFormat
|
||||
SourceSurfaceD2D::GetFormat() const
|
||||
{
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
bool
|
||||
SourceSurfaceD2D::IsValid() const
|
||||
{
|
||||
return mDevice == Factory::GetDirect3D10Device();
|
||||
}
|
||||
|
||||
already_AddRefed<DataSourceSurface>
|
||||
SourceSurfaceD2D::GetDataSurface()
|
||||
{
|
||||
RefPtr<DataSourceSurfaceD2D> result = new DataSourceSurfaceD2D(this);
|
||||
if (result->IsValid()) {
|
||||
return result.forget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
SourceSurfaceD2D::InitFromData(unsigned char *aData,
|
||||
const IntSize &aSize,
|
||||
int32_t aStride,
|
||||
SurfaceFormat aFormat,
|
||||
ID2D1RenderTarget *aRT)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
mFormat = aFormat;
|
||||
mSize = aSize;
|
||||
|
||||
if ((uint32_t)aSize.width > aRT->GetMaximumBitmapSize() ||
|
||||
(uint32_t)aSize.height > aRT->GetMaximumBitmapSize()) {
|
||||
gfxDebug() << "Bitmap does not fit in texture.";
|
||||
return false;
|
||||
}
|
||||
|
||||
D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(aFormat));
|
||||
hr = aRT->CreateBitmap(D2DIntSize(aSize), props, getter_AddRefs(mBitmap));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to create D2D Bitmap for data. Code: " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = mBitmap->CopyFromMemory(nullptr, aData, aStride);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to copy data to D2D bitmap. Code: " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
DrawTargetD2D::mVRAMUsageSS += GetByteSize();
|
||||
mDevice = Factory::GetDirect3D10Device();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SourceSurfaceD2D::InitFromTexture(ID3D10Texture2D *aTexture,
|
||||
SurfaceFormat aFormat,
|
||||
ID2D1RenderTarget *aRT)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
RefPtr<IDXGISurface> surf;
|
||||
|
||||
hr = aTexture->QueryInterface((IDXGISurface**)&surf);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to QI texture to surface. Code: " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
aTexture->GetDesc(&desc);
|
||||
|
||||
mSize = IntSize(desc.Width, desc.Height);
|
||||
mFormat = aFormat;
|
||||
|
||||
D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(aFormat));
|
||||
hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, getter_AddRefs(mBitmap));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to create SharedBitmap. Code: " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
aTexture->GetDevice(getter_AddRefs(mDevice));
|
||||
DrawTargetD2D::mVRAMUsageSS += GetByteSize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SourceSurfaceD2D::GetByteSize() const
|
||||
{
|
||||
return mSize.width * mSize.height * BytesPerPixel(mFormat);
|
||||
}
|
||||
|
||||
DataSourceSurfaceD2D::DataSourceSurfaceD2D(SourceSurfaceD2D* aSourceSurface)
|
||||
: mTexture(nullptr)
|
||||
, mFormat(aSourceSurface->mFormat)
|
||||
, mSize(aSourceSurface->mSize)
|
||||
, mMapped(false)
|
||||
{
|
||||
// We allocate ourselves a regular D3D surface (sourceTexture) and paint the
|
||||
// D2D bitmap into it via a DXGI render target. Then we need to copy
|
||||
// sourceTexture into a staging texture (mTexture), which we will lazily map
|
||||
// to get the data.
|
||||
|
||||
CD3D10_TEXTURE2D_DESC desc(DXGIFormat(mFormat), mSize.width, mSize.height);
|
||||
desc.MipLevels = 1;
|
||||
desc.Usage = D3D10_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
|
||||
RefPtr<ID3D10Texture2D> sourceTexture;
|
||||
HRESULT hr = aSourceSurface->mDevice->CreateTexture2D(&desc, nullptr,
|
||||
getter_AddRefs(sourceTexture));
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to create texture. Code: " << hexa(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<IDXGISurface> dxgiSurface;
|
||||
hr = sourceTexture->QueryInterface((IDXGISurface**)getter_AddRefs(dxgiSurface));
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to create DXGI surface. Code: " << hexa(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties(
|
||||
D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
||||
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
|
||||
|
||||
RefPtr<ID2D1RenderTarget> renderTarget;
|
||||
hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(dxgiSurface,
|
||||
&rtProps,
|
||||
getter_AddRefs(renderTarget));
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to create render target. Code: " << hexa(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
renderTarget->BeginDraw();
|
||||
renderTarget->Clear(D2D1::ColorF(0, 0.0f));
|
||||
if (aSourceSurface->GetFormat() != SurfaceFormat::A8) {
|
||||
renderTarget->DrawBitmap(aSourceSurface->mBitmap,
|
||||
D2D1::RectF(0, 0,
|
||||
Float(mSize.width),
|
||||
Float(mSize.height)));
|
||||
} else {
|
||||
RefPtr<ID2D1SolidColorBrush> brush;
|
||||
renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), getter_AddRefs(brush));
|
||||
renderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
renderTarget->FillOpacityMask(aSourceSurface->mBitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS);
|
||||
}
|
||||
hr = renderTarget->EndDraw();
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to draw bitmap. Code: " << hexa(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE;
|
||||
desc.Usage = D3D10_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
hr = aSourceSurface->mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTexture));
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to create staging texture. Code: " << hexa(hr);
|
||||
mTexture = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
aSourceSurface->mDevice->CopyResource(mTexture, sourceTexture);
|
||||
}
|
||||
|
||||
DataSourceSurfaceD2D::~DataSourceSurfaceD2D()
|
||||
{
|
||||
if (mMapped) {
|
||||
mTexture->Unmap(0);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char*
|
||||
DataSourceSurfaceD2D::GetData()
|
||||
{
|
||||
EnsureMappedTexture();
|
||||
if (!mMapped) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<unsigned char*>(mData.pData);
|
||||
}
|
||||
|
||||
int32_t
|
||||
DataSourceSurfaceD2D::Stride()
|
||||
{
|
||||
EnsureMappedTexture();
|
||||
if (!mMapped) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mData.RowPitch;
|
||||
}
|
||||
|
||||
IntSize
|
||||
DataSourceSurfaceD2D::GetSize() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
SurfaceFormat
|
||||
DataSourceSurfaceD2D::GetFormat() const
|
||||
{
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
bool
|
||||
DataSourceSurfaceD2D::Map(MapType aMapType, MappedSurface *aMappedSurface)
|
||||
{
|
||||
// DataSourceSurfaces used with the new Map API should not be used with GetData!!
|
||||
MOZ_ASSERT(!mMapped);
|
||||
MOZ_ASSERT(!mIsMapped);
|
||||
|
||||
if (!mTexture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D10_MAP mapType;
|
||||
|
||||
if (aMapType == MapType::READ) {
|
||||
mapType = D3D10_MAP_READ;
|
||||
} else if (aMapType == MapType::WRITE) {
|
||||
mapType = D3D10_MAP_WRITE;
|
||||
} else {
|
||||
mapType = D3D10_MAP_READ_WRITE;
|
||||
}
|
||||
|
||||
D3D10_MAPPED_TEXTURE2D map;
|
||||
|
||||
HRESULT hr = mTexture->Map(0, mapType, 0, &map);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Texture map failed with code: " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
aMappedSurface->mData = (uint8_t*)map.pData;
|
||||
aMappedSurface->mStride = map.RowPitch;
|
||||
mIsMapped = !!aMappedSurface->mData;
|
||||
|
||||
return mIsMapped;
|
||||
}
|
||||
|
||||
void
|
||||
DataSourceSurfaceD2D::Unmap()
|
||||
{
|
||||
MOZ_ASSERT(mIsMapped);
|
||||
|
||||
mIsMapped = false;
|
||||
mTexture->Unmap(0);
|
||||
}
|
||||
|
||||
void
|
||||
DataSourceSurfaceD2D::EnsureMappedTexture()
|
||||
{
|
||||
// Do not use GetData() after having used Map!
|
||||
MOZ_ASSERT(!mIsMapped);
|
||||
|
||||
if (mMapped ||
|
||||
!mTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
HRESULT hr = mTexture->Map(0, D3D10_MAP_READ, 0, &mData);
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to map texture. Code: " << hexa(hr);
|
||||
mTexture = nullptr;
|
||||
} else {
|
||||
mMapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_SOURCESURFACED2D_H_
|
||||
#define MOZILLA_GFX_SOURCESURFACED2D_H_
|
||||
|
||||
#include "2D.h"
|
||||
#include "HelpersD2D.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
class DataSourceSurfaceD2D;
|
||||
|
||||
class SourceSurfaceD2D : public SourceSurface
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceD2D)
|
||||
SourceSurfaceD2D();
|
||||
~SourceSurfaceD2D();
|
||||
|
||||
virtual SurfaceType GetType() const { return SurfaceType::D2D1_BITMAP; }
|
||||
virtual IntSize GetSize() const;
|
||||
virtual SurfaceFormat GetFormat() const;
|
||||
virtual bool IsValid() const;
|
||||
|
||||
virtual already_AddRefed<DataSourceSurface> GetDataSurface();
|
||||
|
||||
ID2D1Bitmap *GetBitmap() { return mBitmap; }
|
||||
|
||||
bool InitFromData(unsigned char *aData,
|
||||
const IntSize &aSize,
|
||||
int32_t aStride,
|
||||
SurfaceFormat aFormat,
|
||||
ID2D1RenderTarget *aRT);
|
||||
bool InitFromTexture(ID3D10Texture2D *aTexture,
|
||||
SurfaceFormat aFormat,
|
||||
ID2D1RenderTarget *aRT);
|
||||
private:
|
||||
friend class DrawTargetD2D;
|
||||
friend class DataSourceSurfaceD2D;
|
||||
|
||||
uint32_t GetByteSize() const;
|
||||
|
||||
RefPtr<ID2D1Bitmap> mBitmap;
|
||||
// We need to keep this pointer here to check surface validity.
|
||||
RefPtr<ID3D10Device> mDevice;
|
||||
SurfaceFormat mFormat;
|
||||
IntSize mSize;
|
||||
};
|
||||
|
||||
|
||||
class DataSourceSurfaceD2D : public DataSourceSurface
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceD2D)
|
||||
DataSourceSurfaceD2D(SourceSurfaceD2D* aSourceSurface);
|
||||
virtual ~DataSourceSurfaceD2D();
|
||||
|
||||
virtual unsigned char* GetData();
|
||||
virtual int32_t Stride();
|
||||
virtual IntSize GetSize() const;
|
||||
virtual SurfaceFormat GetFormat() const;
|
||||
virtual bool Map(MapType, MappedSurface *aMappedSurface);
|
||||
virtual void Unmap();
|
||||
|
||||
bool IsValid()
|
||||
{
|
||||
return mTexture;
|
||||
}
|
||||
|
||||
private:
|
||||
void EnsureMappedTexture();
|
||||
|
||||
RefPtr<ID3D10Texture2D> mTexture;
|
||||
|
||||
D3D10_MAPPED_TEXTURE2D mData;
|
||||
|
||||
SurfaceFormat mFormat;
|
||||
IntSize mSize;
|
||||
bool mMapped;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MOZILLA_GFX_SOURCESURFACED2D_H_ */
|
|
@ -1,325 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SourceSurfaceD2DTarget.h"
|
||||
#include "Logging.h"
|
||||
#include "DrawTargetD2D.h"
|
||||
#include "Tools.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
SourceSurfaceD2DTarget::SourceSurfaceD2DTarget(DrawTargetD2D* aDrawTarget,
|
||||
ID3D10Texture2D* aTexture,
|
||||
SurfaceFormat aFormat)
|
||||
: mDrawTarget(aDrawTarget)
|
||||
, mTexture(aTexture)
|
||||
, mFormat(aFormat)
|
||||
, mOwnsCopy(false)
|
||||
{
|
||||
}
|
||||
|
||||
SourceSurfaceD2DTarget::~SourceSurfaceD2DTarget()
|
||||
{
|
||||
// We don't need to do anything special here to notify our mDrawTarget. It must
|
||||
// already have cleared its mSnapshot field, otherwise this object would
|
||||
// be kept alive.
|
||||
if (mOwnsCopy) {
|
||||
IntSize size = GetSize();
|
||||
|
||||
DrawTargetD2D::mVRAMUsageSS -= size.width * size.height * BytesPerPixel(mFormat);
|
||||
}
|
||||
}
|
||||
|
||||
IntSize
|
||||
SourceSurfaceD2DTarget::GetSize() const
|
||||
{
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
mTexture->GetDesc(&desc);
|
||||
|
||||
return IntSize(desc.Width, desc.Height);
|
||||
}
|
||||
|
||||
SurfaceFormat
|
||||
SourceSurfaceD2DTarget::GetFormat() const
|
||||
{
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
already_AddRefed<DataSourceSurface>
|
||||
SourceSurfaceD2DTarget::GetDataSurface()
|
||||
{
|
||||
RefPtr<DataSourceSurfaceD2DTarget> dataSurf =
|
||||
new DataSourceSurfaceD2DTarget(mFormat);
|
||||
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
mTexture->GetDesc(&desc);
|
||||
|
||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
|
||||
desc.Usage = D3D10_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
if (!Factory::GetDirect3D10Device()) {
|
||||
gfxCriticalError() << "Invalid D3D10 device in D2D target surface (GDS)";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(dataSurf->mTexture));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxDebug() << "Failed to create staging texture for SourceSurface. Code: " << hexa(hr);
|
||||
return nullptr;
|
||||
}
|
||||
Factory::GetDirect3D10Device()->CopyResource(dataSurf->mTexture, mTexture);
|
||||
|
||||
return dataSurf.forget();
|
||||
}
|
||||
|
||||
void*
|
||||
SourceSurfaceD2DTarget::GetNativeSurface(NativeSurfaceType aType)
|
||||
{
|
||||
if (aType == NativeSurfaceType::D3D10_TEXTURE) {
|
||||
return static_cast<void*>(mTexture.get());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D10ShaderResourceView*
|
||||
SourceSurfaceD2DTarget::GetSRView()
|
||||
{
|
||||
if (mSRView) {
|
||||
return mSRView;
|
||||
}
|
||||
|
||||
if (!Factory::GetDirect3D10Device()) {
|
||||
gfxCriticalError() << "Invalid D3D10 device in D2D target surface (SRV)";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HRESULT hr = Factory::GetDirect3D10Device()->CreateShaderResourceView(mTexture, nullptr, getter_AddRefs(mSRView));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to create ShaderResourceView. Code: " << hexa(hr);
|
||||
}
|
||||
|
||||
return mSRView;
|
||||
}
|
||||
|
||||
void
|
||||
SourceSurfaceD2DTarget::DrawTargetWillChange()
|
||||
{
|
||||
RefPtr<ID3D10Texture2D> oldTexture = mTexture;
|
||||
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
mTexture->GetDesc(&desc);
|
||||
|
||||
// Our original texture might implement the keyed mutex flag. We shouldn't
|
||||
// need that here. We actually specifically don't want it since we don't lock
|
||||
// our texture for usage!
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
// Get a copy of the surface data so the content at snapshot time was saved.
|
||||
Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTexture));
|
||||
Factory::GetDirect3D10Device()->CopyResource(mTexture, oldTexture);
|
||||
|
||||
mBitmap = nullptr;
|
||||
|
||||
DrawTargetD2D::mVRAMUsageSS += desc.Width * desc.Height * BytesPerPixel(mFormat);
|
||||
mOwnsCopy = true;
|
||||
|
||||
// We now no longer depend on the source surface content remaining the same.
|
||||
MarkIndependent();
|
||||
}
|
||||
|
||||
ID2D1Bitmap*
|
||||
SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT)
|
||||
{
|
||||
if (mBitmap) {
|
||||
return mBitmap;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
mTexture->GetDesc(&desc);
|
||||
|
||||
IntSize size(desc.Width, desc.Height);
|
||||
|
||||
RefPtr<IDXGISurface> surf;
|
||||
hr = mTexture->QueryInterface((IDXGISurface**)getter_AddRefs(surf));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to query interface texture to DXGISurface. Code: " << hexa(hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(mFormat));
|
||||
hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, getter_AddRefs(mBitmap));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
// This seems to happen for SurfaceFormat::A8 sometimes...
|
||||
hr = aRT->CreateBitmap(D2D1::SizeU(desc.Width, desc.Height),
|
||||
D2D1::BitmapProperties(D2DPixelFormat(mFormat)),
|
||||
getter_AddRefs(mBitmap));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed in CreateBitmap. Code: " << hexa(hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ID2D1RenderTarget> rt;
|
||||
|
||||
if (mDrawTarget) {
|
||||
rt = mDrawTarget->mRT;
|
||||
}
|
||||
|
||||
if (!rt) {
|
||||
// Okay, we already separated from our drawtarget. And we're an A8
|
||||
// surface the only way we can get to a bitmap is by creating a
|
||||
// a rendertarget and from there copying to a bitmap! Terrible!
|
||||
RefPtr<IDXGISurface> surface;
|
||||
|
||||
hr = mTexture->QueryInterface((IDXGISurface**)getter_AddRefs(surface));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to QI texture to surface.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D2D1_RENDER_TARGET_PROPERTIES props =
|
||||
D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2DPixelFormat(mFormat));
|
||||
hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(surface, props, getter_AddRefs(rt));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to create D2D render target for texture.";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mBitmap->CopyFromRenderTarget(nullptr, rt, nullptr);
|
||||
return mBitmap;
|
||||
}
|
||||
|
||||
return mBitmap;
|
||||
}
|
||||
|
||||
void
|
||||
SourceSurfaceD2DTarget::MarkIndependent()
|
||||
{
|
||||
if (mDrawTarget) {
|
||||
MOZ_ASSERT(mDrawTarget->mSnapshot == this);
|
||||
mDrawTarget->mSnapshot = nullptr;
|
||||
mDrawTarget = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DataSourceSurfaceD2DTarget::DataSourceSurfaceD2DTarget(SurfaceFormat aFormat)
|
||||
: mFormat(aFormat)
|
||||
, mMapped(false)
|
||||
{
|
||||
}
|
||||
|
||||
DataSourceSurfaceD2DTarget::~DataSourceSurfaceD2DTarget()
|
||||
{
|
||||
if (mMapped) {
|
||||
mTexture->Unmap(0);
|
||||
}
|
||||
}
|
||||
|
||||
IntSize
|
||||
DataSourceSurfaceD2DTarget::GetSize() const
|
||||
{
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
mTexture->GetDesc(&desc);
|
||||
|
||||
return IntSize(desc.Width, desc.Height);
|
||||
}
|
||||
|
||||
SurfaceFormat
|
||||
DataSourceSurfaceD2DTarget::GetFormat() const
|
||||
{
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
DataSourceSurfaceD2DTarget::GetData()
|
||||
{
|
||||
EnsureMapped();
|
||||
|
||||
return (unsigned char*)mMap.pData;
|
||||
}
|
||||
|
||||
int32_t
|
||||
DataSourceSurfaceD2DTarget::Stride()
|
||||
{
|
||||
EnsureMapped();
|
||||
return mMap.RowPitch;
|
||||
}
|
||||
|
||||
bool
|
||||
DataSourceSurfaceD2DTarget::Map(MapType aMapType, MappedSurface *aMappedSurface)
|
||||
{
|
||||
// DataSourceSurfaces used with the new Map API should not be used with GetData!!
|
||||
MOZ_ASSERT(!mMapped);
|
||||
MOZ_ASSERT(!mIsMapped);
|
||||
|
||||
if (!mTexture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D10_MAP mapType;
|
||||
|
||||
if (aMapType == MapType::READ) {
|
||||
mapType = D3D10_MAP_READ;
|
||||
} else if (aMapType == MapType::WRITE) {
|
||||
mapType = D3D10_MAP_WRITE;
|
||||
} else {
|
||||
mapType = D3D10_MAP_READ_WRITE;
|
||||
}
|
||||
|
||||
D3D10_MAPPED_TEXTURE2D map;
|
||||
|
||||
HRESULT hr = mTexture->Map(0, mapType, 0, &map);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Texture map failed with code: " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
aMappedSurface->mData = (uint8_t*)map.pData;
|
||||
aMappedSurface->mStride = map.RowPitch;
|
||||
mIsMapped = !!aMappedSurface->mData;
|
||||
|
||||
return mIsMapped;
|
||||
}
|
||||
|
||||
void
|
||||
DataSourceSurfaceD2DTarget::Unmap()
|
||||
{
|
||||
MOZ_ASSERT(mIsMapped);
|
||||
|
||||
mIsMapped = false;
|
||||
mTexture->Unmap(0);
|
||||
}
|
||||
|
||||
void
|
||||
DataSourceSurfaceD2DTarget::EnsureMapped()
|
||||
{
|
||||
// Do not use GetData() after having used Map!
|
||||
MOZ_ASSERT(!mIsMapped);
|
||||
if (!mMapped) {
|
||||
HRESULT hr = mTexture->Map(0, D3D10_MAP_READ, 0, &mMap);
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to map texture to memory. Code: " << hexa(hr);
|
||||
return;
|
||||
}
|
||||
mMapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* 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/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_SOURCESURFACED2DTARGET_H_
|
||||
#define MOZILLA_GFX_SOURCESURFACED2DTARGET_H_
|
||||
|
||||
#include "2D.h"
|
||||
#include "HelpersD2D.h"
|
||||
#include <vector>
|
||||
#include <d3d10_1.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
class DrawTargetD2D;
|
||||
|
||||
class SourceSurfaceD2DTarget : public SourceSurface
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceD2DTarget)
|
||||
SourceSurfaceD2DTarget(DrawTargetD2D* aDrawTarget, ID3D10Texture2D* aTexture,
|
||||
SurfaceFormat aFormat);
|
||||
~SourceSurfaceD2DTarget();
|
||||
|
||||
virtual SurfaceType GetType() const { return SurfaceType::D2D1_DRAWTARGET; }
|
||||
virtual IntSize GetSize() const;
|
||||
virtual SurfaceFormat GetFormat() const;
|
||||
virtual already_AddRefed<DataSourceSurface> GetDataSurface();
|
||||
virtual void *GetNativeSurface(NativeSurfaceType aType);
|
||||
|
||||
DrawTargetD2D* GetDT() { return mDrawTarget; }
|
||||
ID2D1Bitmap *GetBitmap(ID2D1RenderTarget *aRT);
|
||||
|
||||
private:
|
||||
friend class DrawTargetD2D;
|
||||
|
||||
ID3D10ShaderResourceView *GetSRView();
|
||||
|
||||
// This function is called by the draw target this texture belongs to when
|
||||
// it is about to be changed. The texture will be required to make a copy
|
||||
// of itself when this happens.
|
||||
void DrawTargetWillChange();
|
||||
|
||||
// This will mark the surface as no longer depending on its drawtarget,
|
||||
// this may happen on destruction or copying.
|
||||
void MarkIndependent();
|
||||
|
||||
RefPtr<ID3D10ShaderResourceView> mSRView;
|
||||
RefPtr<ID2D1Bitmap> mBitmap;
|
||||
// Non-null if this is a "lazy copy" of the given draw target.
|
||||
// Null if we've made a copy. The target is not kept alive, otherwise we'd
|
||||
// have leaks since it might keep us alive. If the target is destroyed, it
|
||||
// will notify us.
|
||||
DrawTargetD2D* mDrawTarget;
|
||||
mutable RefPtr<ID3D10Texture2D> mTexture;
|
||||
SurfaceFormat mFormat;
|
||||
bool mOwnsCopy;
|
||||
};
|
||||
|
||||
class DataSourceSurfaceD2DTarget : public DataSourceSurface
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceD2DTarget)
|
||||
DataSourceSurfaceD2DTarget(SurfaceFormat aFormat);
|
||||
~DataSourceSurfaceD2DTarget();
|
||||
|
||||
virtual SurfaceType GetType() const { return SurfaceType::DATA; }
|
||||
virtual IntSize GetSize() const;
|
||||
virtual SurfaceFormat GetFormat() const;
|
||||
virtual uint8_t *GetData();
|
||||
virtual int32_t Stride();
|
||||
virtual bool Map(MapType, MappedSurface *aMappedSurface);
|
||||
virtual void Unmap();
|
||||
|
||||
private:
|
||||
friend class SourceSurfaceD2DTarget;
|
||||
void EnsureMapped();
|
||||
|
||||
mutable RefPtr<ID3D10Texture2D> mTexture;
|
||||
SurfaceFormat mFormat;
|
||||
D3D10_MAPPED_TEXTURE2D mMap;
|
||||
bool mMapped;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MOZILLA_GFX_SOURCESURFACED2DTARGET_H_ */
|
|
@ -123,7 +123,7 @@ enum class DrawTargetType : int8_t {
|
|||
|
||||
enum class BackendType : int8_t {
|
||||
NONE = 0,
|
||||
DIRECT2D,
|
||||
DIRECT2D, // Used for version independent D2D objects.
|
||||
COREGRAPHICS,
|
||||
COREGRAPHICS_ACCELERATED,
|
||||
CAIRO,
|
||||
|
|
|
@ -66,7 +66,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'):
|
|||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
SOURCES += [
|
||||
'DrawTargetD2D.cpp',
|
||||
'DrawTargetD2D1.cpp',
|
||||
'ExtendInputEffectD2D1.cpp',
|
||||
'FilterNodeD2D1.cpp',
|
||||
|
@ -77,9 +76,7 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|||
'RadialGradientEffectD2D1.cpp',
|
||||
'ScaledFontDWrite.cpp',
|
||||
'ScaledFontWin.cpp',
|
||||
'SourceSurfaceD2D.cpp',
|
||||
'SourceSurfaceD2D1.cpp',
|
||||
'SourceSurfaceD2DTarget.cpp',
|
||||
]
|
||||
DEFINES['WIN32'] = True
|
||||
|
||||
|
|
|
@ -538,7 +538,7 @@ GLScreenBuffer::Swap(const gfx::IntSize& size)
|
|||
if (!newBack)
|
||||
return false;
|
||||
|
||||
// In the case of DXGL interop, the new surface needs to be acquired before
|
||||
// In the case of DXGL interop, the new surface needs to be acquired before
|
||||
// it is attached so that the interop surface is locked, which populates
|
||||
// the GL renderbuffer. This results in the renderbuffer being ready and
|
||||
// attachment to framebuffer succeeds in Attach() call.
|
||||
|
@ -828,10 +828,7 @@ DrawBuffer::Create(GLContext* const gl,
|
|||
gl->fGenFramebuffers(1, &fb);
|
||||
gl->AttachBuffersToFB(0, colorMSRB, depthRB, stencilRB, fb);
|
||||
|
||||
GLsizei samples = formats.samples;
|
||||
if (!samples)
|
||||
samples = 1;
|
||||
|
||||
const GLsizei samples = formats.samples;
|
||||
UniquePtr<DrawBuffer> ret( new DrawBuffer(gl, size, samples, fb, colorMSRB,
|
||||
depthRB, stencilRB) );
|
||||
|
||||
|
|
|
@ -206,7 +206,7 @@ public:
|
|||
|
||||
GLsizei Samples() const {
|
||||
if (!mDraw)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
return mDraw->mSamples;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ struct DeviceInitData
|
|||
bool useD3D11WARP;
|
||||
bool useD3D11ImageBridge;
|
||||
bool d3d11TextureSharingWorks;
|
||||
bool useD2D;
|
||||
bool useD2D1;
|
||||
DxgiAdapterDesc adapter;
|
||||
};
|
||||
|
|
|
@ -40,13 +40,13 @@ public:
|
|||
* to have remained the same since the call to
|
||||
* ReturnAndUseDT.
|
||||
*/
|
||||
virtual gfx::DrawTarget* GetDT(const gfx::IntRect& aPersistedRect) = 0;
|
||||
virtual already_AddRefed<gfx::DrawTarget> GetDT(const gfx::IntRect& aPersistedRect) = 0;
|
||||
/**
|
||||
* Return a DrawTarget to the PersistentBufferProvider and indicate the
|
||||
* contents of this DrawTarget is to be considered current by the
|
||||
* BufferProvider
|
||||
* BufferProvider. The caller should forget any references to the DrawTarget.
|
||||
*/
|
||||
virtual bool ReturnAndUseDT(gfx::DrawTarget* aDT) = 0;
|
||||
virtual bool ReturnAndUseDT(already_AddRefed<gfx::DrawTarget> aDT) = 0;
|
||||
|
||||
virtual already_AddRefed<gfx::SourceSurface> GetSnapshot() = 0;
|
||||
protected:
|
||||
|
@ -63,8 +63,15 @@ public:
|
|||
|
||||
bool IsValid() { return !!mDrawTarget; }
|
||||
virtual LayersBackend GetType() { return LayersBackend::LAYERS_BASIC; }
|
||||
gfx::DrawTarget* GetDT(const gfx::IntRect& aPersistedRect) { return mDrawTarget; }
|
||||
bool ReturnAndUseDT(gfx::DrawTarget* aDT) { MOZ_ASSERT(mDrawTarget == aDT); return true; }
|
||||
already_AddRefed<gfx::DrawTarget> GetDT(const gfx::IntRect& aPersistedRect) {
|
||||
RefPtr<gfx::DrawTarget> dt(mDrawTarget);
|
||||
return dt.forget();
|
||||
}
|
||||
bool ReturnAndUseDT(already_AddRefed<gfx::DrawTarget> aDT) {
|
||||
RefPtr<gfx::DrawTarget> dt(aDT);
|
||||
MOZ_ASSERT(mDrawTarget == dt);
|
||||
return true;
|
||||
}
|
||||
virtual already_AddRefed<gfx::SourceSurface> GetSnapshot() { return mDrawTarget->Snapshot(); }
|
||||
private:
|
||||
RefPtr<gfx::DrawTarget> mDrawTarget;
|
||||
|
|
|
@ -1051,9 +1051,11 @@ APZCTreeManager::ProcessWheelEvent(WidgetWheelEvent& aEvent,
|
|||
uint64_t* aOutInputBlockId)
|
||||
{
|
||||
ScrollWheelInput::ScrollMode scrollMode = ScrollWheelInput::SCROLLMODE_INSTANT;
|
||||
if ((aEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE ||
|
||||
aEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE) &&
|
||||
gfxPrefs::SmoothScrollEnabled() && gfxPrefs::WheelSmoothScrollEnabled())
|
||||
if (gfxPrefs::SmoothScrollEnabled() &&
|
||||
((aEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE &&
|
||||
gfxPrefs::WheelSmoothScrollEnabled()) ||
|
||||
(aEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE &&
|
||||
gfxPrefs::PageSmoothScrollEnabled())))
|
||||
{
|
||||
scrollMode = ScrollWheelInput::SCROLLMODE_SMOOTH;
|
||||
}
|
||||
|
|
|
@ -1792,8 +1792,7 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
|
|||
|
||||
nsPoint initialPosition = CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset());
|
||||
StartAnimation(new WheelScrollAnimation(
|
||||
*this,
|
||||
initialPosition));
|
||||
*this, initialPosition, aEvent.mDeltaType));
|
||||
}
|
||||
|
||||
nsPoint deltaInAppUnits =
|
||||
|
|
|
@ -13,10 +13,13 @@
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
WheelScrollAnimation::WheelScrollAnimation(AsyncPanZoomController& aApzc, const nsPoint& aInitialPosition)
|
||||
WheelScrollAnimation::WheelScrollAnimation(AsyncPanZoomController& aApzc,
|
||||
const nsPoint& aInitialPosition,
|
||||
ScrollWheelInput::ScrollDeltaType aDeltaType)
|
||||
: AsyncScrollBase(aInitialPosition)
|
||||
, mApzc(aApzc)
|
||||
, mFinalDestination(aInitialPosition)
|
||||
, mDeltaType(aDeltaType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -86,8 +89,21 @@ WheelScrollAnimation::InitPreferences(TimeStamp aTime)
|
|||
return;
|
||||
}
|
||||
|
||||
mOriginMaxMS = clamped(gfxPrefs::WheelSmoothScrollMaxDurationMs(), 0, 10000);
|
||||
mOriginMinMS = clamped(gfxPrefs::WheelSmoothScrollMinDurationMs(), 0, mOriginMaxMS);
|
||||
switch (mDeltaType) {
|
||||
case ScrollWheelInput::SCROLLDELTA_PAGE:
|
||||
mOriginMaxMS = clamped(gfxPrefs::PageSmoothScrollMaxDurationMs(), 0, 10000);
|
||||
mOriginMinMS = clamped(gfxPrefs::PageSmoothScrollMinDurationMs(), 0, mOriginMaxMS);
|
||||
break;
|
||||
case ScrollWheelInput::SCROLLDELTA_PIXEL:
|
||||
mOriginMaxMS = clamped(gfxPrefs::PixelSmoothScrollMaxDurationMs(), 0, 10000);
|
||||
mOriginMinMS = clamped(gfxPrefs::PixelSmoothScrollMinDurationMs(), 0, mOriginMaxMS);
|
||||
break;
|
||||
case ScrollWheelInput::SCROLLDELTA_LINE:
|
||||
default:
|
||||
mOriginMaxMS = clamped(gfxPrefs::WheelSmoothScrollMaxDurationMs(), 0, 10000);
|
||||
mOriginMinMS = clamped(gfxPrefs::WheelSmoothScrollMinDurationMs(), 0, mOriginMaxMS);
|
||||
break;
|
||||
}
|
||||
|
||||
// The pref is 100-based int percentage, while mIntervalRatio is 1-based ratio
|
||||
mIntervalRatio = ((double)gfxPrefs::SmoothScrollDurationToIntervalRatio()) / 100.0;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "AsyncPanZoomAnimation.h"
|
||||
#include "AsyncScrollBase.h"
|
||||
#include "InputData.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
@ -20,7 +21,9 @@ class WheelScrollAnimation
|
|||
public AsyncScrollBase
|
||||
{
|
||||
public:
|
||||
WheelScrollAnimation(AsyncPanZoomController& aApzc, const nsPoint& aInitialPosition);
|
||||
WheelScrollAnimation(AsyncPanZoomController& aApzc,
|
||||
const nsPoint& aInitialPosition,
|
||||
ScrollWheelInput::ScrollDeltaType aDeltaType);
|
||||
|
||||
bool DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta) override;
|
||||
void Update(TimeStamp aTime, nsPoint aDelta, const nsSize& aCurrentVelocity);
|
||||
|
@ -35,6 +38,7 @@ private:
|
|||
private:
|
||||
AsyncPanZoomController& mApzc;
|
||||
nsPoint mFinalDestination;
|
||||
ScrollWheelInput::ScrollDeltaType mDeltaType;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
# The following tests test the async positioning of the scrollbars.
|
||||
# Basic root-frame scrollbar with async scrolling
|
||||
chaos-mode skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html
|
||||
chaos-mode skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html
|
||||
chaos-mode skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html
|
||||
chaos-mode skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html
|
||||
chaos-mode skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html
|
||||
chaos-mode skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html
|
||||
skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html
|
||||
skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html
|
||||
skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html
|
||||
skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html
|
||||
skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html
|
||||
skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html
|
||||
|
||||
# Different async zoom levels. Since the scrollthumb gets async-scaled in the
|
||||
# compositor, the border-radius ends of the scrollthumb are going to be a little
|
||||
# off, hence the fuzzy-if clauses.
|
||||
chaos-mode skip-if(!asyncZoom) fuzzy-if(B2G,98,82) == async-scrollbar-zoom-1.html async-scrollbar-zoom-1-ref.html
|
||||
chaos-mode skip-if(!asyncZoom) fuzzy-if(B2G,94,146) == async-scrollbar-zoom-2.html async-scrollbar-zoom-2-ref.html
|
||||
skip-if(!asyncZoom) fuzzy-if(B2G,98,82) == async-scrollbar-zoom-1.html async-scrollbar-zoom-1-ref.html
|
||||
skip-if(!asyncZoom) fuzzy-if(B2G,94,146) == async-scrollbar-zoom-2.html async-scrollbar-zoom-2-ref.html
|
||||
|
||||
# Meta-viewport tag support
|
||||
chaos-mode skip-if(!asyncZoom) == initial-scale-1.html initial-scale-1-ref.html
|
||||
skip-if(!asyncZoom) == initial-scale-1.html initial-scale-1-ref.html
|
||||
|
|
|
@ -28,6 +28,7 @@ ClientTiledPaintedLayer::ClientTiledPaintedLayer(ClientLayerManager* const aMana
|
|||
ClientLayerManager::PaintedLayerCreationHint aCreationHint)
|
||||
: PaintedLayer(aManager, static_cast<ClientLayer*>(this), aCreationHint)
|
||||
, mContentClient()
|
||||
, mHaveSingleTiledContentClient(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientTiledPaintedLayer);
|
||||
mPaintData.mLastScrollOffset = ParentLayerPoint(0, 0);
|
||||
|
@ -411,18 +412,26 @@ ClientTiledPaintedLayer::RenderLayer()
|
|||
void *data = ClientManager()->GetPaintedLayerCallbackData();
|
||||
|
||||
IntSize layerSize = mVisibleRegion.ToUnknownRegion().GetBounds().Size();
|
||||
if (mContentClient && !mContentClient->SupportsLayerSize(layerSize, ClientManager())) {
|
||||
IntSize tileSize(gfxPlatform::GetPlatform()->GetTileWidth(),
|
||||
gfxPlatform::GetPlatform()->GetTileHeight());
|
||||
|
||||
bool wantSingleTiledContentClient =
|
||||
(mCreationHint == LayerManager::NONE || layerSize <= tileSize) &&
|
||||
SingleTiledContentClient::ClientSupportsLayerSize(layerSize, ClientManager()) &&
|
||||
gfxPrefs::LayersSingleTileEnabled();
|
||||
|
||||
if (mContentClient && mHaveSingleTiledContentClient && !wantSingleTiledContentClient) {
|
||||
mContentClient = nullptr;
|
||||
mValidRegion.SetEmpty();
|
||||
}
|
||||
|
||||
if (!mContentClient) {
|
||||
if (mCreationHint == LayerManager::NONE &&
|
||||
SingleTiledContentClient::ClientSupportsLayerSize(layerSize, ClientManager()) &&
|
||||
gfxPrefs::LayersSingleTileEnabled()) {
|
||||
if (wantSingleTiledContentClient) {
|
||||
mContentClient = new SingleTiledContentClient(this, ClientManager());
|
||||
mHaveSingleTiledContentClient = true;
|
||||
} else {
|
||||
mContentClient = new MultiTiledContentClient(this, ClientManager());
|
||||
mHaveSingleTiledContentClient = false;
|
||||
}
|
||||
|
||||
mContentClient->Connect();
|
||||
|
|
|
@ -133,6 +133,9 @@ private:
|
|||
void EndPaint();
|
||||
|
||||
RefPtr<TiledContentClient> mContentClient;
|
||||
// Flag to indicate if mContentClient is a SingleTiledContentClient. This is
|
||||
// only valid when mContentClient is non-null.
|
||||
bool mHaveSingleTiledContentClient;
|
||||
nsIntRegion mLowPrecisionValidRegion;
|
||||
BasicTiledLayerPaintData mPaintData;
|
||||
};
|
||||
|
|
|
@ -73,7 +73,7 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
|
|||
|
||||
#ifdef XP_WIN
|
||||
if (backend == LayersBackend::LAYERS_D3D11) {
|
||||
useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
|
||||
useDoubleBuffering = gfxWindowsPlatform::GetPlatform()->GetRenderMode() == gfxWindowsPlatform::RENDER_DIRECT2D;
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
|
|
|
@ -46,12 +46,6 @@ SingleTiledContentClient::ClientSupportsLayerSize(const gfx::IntSize& aSize, Cli
|
|||
return aSize.width <= maxTextureSize && aSize.height <= maxTextureSize;
|
||||
}
|
||||
|
||||
bool
|
||||
SingleTiledContentClient::SupportsLayerSize(const gfx::IntSize& aSize, ClientLayerManager* aManager) const
|
||||
{
|
||||
return ClientSupportsLayerSize(aSize, aManager);
|
||||
}
|
||||
|
||||
ClientSingleTiledLayerBuffer::ClientSingleTiledLayerBuffer(ClientTiledPaintedLayer* aPaintedLayer,
|
||||
CompositableClient* aCompositableClient,
|
||||
ClientLayerManager* aManager)
|
||||
|
|
|
@ -127,8 +127,6 @@ public:
|
|||
virtual ClientTiledLayerBuffer* GetTiledBuffer() override { return mTiledBuffer; }
|
||||
virtual ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() override { return nullptr; }
|
||||
|
||||
virtual bool SupportsLayerSize(const gfx::IntSize& aSize, ClientLayerManager* aManager) const override;
|
||||
|
||||
private:
|
||||
RefPtr<ClientSingleTiledLayerBuffer> mTiledBuffer;
|
||||
};
|
||||
|
|
|
@ -628,9 +628,6 @@ public:
|
|||
};
|
||||
virtual void UpdatedBuffer(TiledBufferType aType) = 0;
|
||||
|
||||
virtual bool SupportsLayerSize(const gfx::IntSize& aSize, ClientLayerManager* aManager) const
|
||||
{ return true; }
|
||||
|
||||
private:
|
||||
const char* mName;
|
||||
};
|
||||
|
|
|
@ -253,31 +253,6 @@ D3D11TextureData::~D3D11TextureData()
|
|||
#endif
|
||||
}
|
||||
|
||||
D3D10TextureData::D3D10TextureData(ID3D10Texture2D* aTexture,
|
||||
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
bool aNeedsClear, bool aNeedsClearWhite,
|
||||
bool aIsForOutOfBandContent)
|
||||
: DXGITextureData(aSize, aFormat, aNeedsClear, aNeedsClearWhite, aIsForOutOfBandContent)
|
||||
, mTexture(aTexture)
|
||||
{
|
||||
MOZ_ASSERT(aTexture);
|
||||
mHasSynchronization = HasKeyedMutex(aTexture);
|
||||
}
|
||||
|
||||
D3D10TextureData::~D3D10TextureData()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// An Azure DrawTarget needs to be locked when it gets nullptr'ed as this is
|
||||
// when it calls EndDraw. This EndDraw should not execute anything so it
|
||||
// shouldn't -really- need the lock but the debug layer chokes on this.
|
||||
if (mDrawTarget) {
|
||||
Lock(OpenMode::OPEN_NONE, nullptr);
|
||||
mDrawTarget = nullptr;
|
||||
Unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
D3D11TextureData::Lock(OpenMode aMode, FenceHandle*)
|
||||
{
|
||||
|
@ -295,23 +270,6 @@ D3D11TextureData::Lock(OpenMode aMode, FenceHandle*)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
D3D10TextureData::Lock(OpenMode aMode, FenceHandle*)
|
||||
{
|
||||
if (!LockD3DTexture(mTexture.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_IsMainThread() && !mIsForOutOfBandContent) {
|
||||
if (!PrepareDrawTargetInLock(aMode)) {
|
||||
Unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DXGITextureData::PrepareDrawTargetInLock(OpenMode aMode)
|
||||
{
|
||||
|
@ -342,12 +300,6 @@ D3D11TextureData::Unlock()
|
|||
UnlockD3DTexture(mTexture.get());
|
||||
}
|
||||
|
||||
void
|
||||
D3D10TextureData::Unlock()
|
||||
{
|
||||
UnlockD3DTexture(mTexture.get());
|
||||
}
|
||||
|
||||
void
|
||||
D3D11TextureData::SyncWithObject(SyncObject* aSyncObject)
|
||||
{
|
||||
|
@ -361,19 +313,6 @@ D3D11TextureData::SyncWithObject(SyncObject* aSyncObject)
|
|||
sync->RegisterTexture(mTexture);
|
||||
}
|
||||
|
||||
void
|
||||
D3D10TextureData::SyncWithObject(SyncObject* aSyncObject)
|
||||
{
|
||||
if (!aSyncObject || !NS_IsMainThread()) {
|
||||
// When off the main thread we sync using a keyed mutex per texture.
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aSyncObject->GetSyncType() == SyncObject::SyncType::D3D11);
|
||||
SyncObjectD3D11* sync = static_cast<SyncObjectD3D11*>(aSyncObject);
|
||||
sync->RegisterTexture(mTexture);
|
||||
}
|
||||
|
||||
bool
|
||||
DXGITextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
|
@ -393,34 +332,6 @@ DXGITextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
D3D10TextureData::ReadBack(TextureReadbackSink* aReadbackSinc)
|
||||
{
|
||||
if (NS_IsMainThread() && aReadbackSinc && mTexture) {
|
||||
ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
|
||||
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
mTexture->GetDesc(&desc);
|
||||
desc.BindFlags = 0;
|
||||
desc.Usage = D3D10_USAGE_STAGING;
|
||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
RefPtr<ID3D10Texture2D> tex;
|
||||
HRESULT hr = device->CreateTexture2D(&desc, nullptr, getter_AddRefs(tex));
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
device->CopyResource(tex, mTexture);
|
||||
gfxWindowsPlatform::GetPlatform()->GetReadbackManager()->PostTask(tex, aReadbackSinc);
|
||||
} else {
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(mSize))) << "[D3D11] CreateTexture2D failure " << mSize << " Code: " << gfx::hexa(hr);
|
||||
aReadbackSinc->ProcessReadback(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DXGITextureData*
|
||||
DXGITextureData::Create(IntSize aSize, SurfaceFormat aFormat, TextureAllocationFlags aFlags)
|
||||
{
|
||||
|
@ -429,19 +340,7 @@ DXGITextureData::Create(IntSize aSize, SurfaceFormat aFormat, TextureAllocationF
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
gfxWindowsPlatform* windowsPlatform = gfxWindowsPlatform::GetPlatform();
|
||||
// When we're not on the main thread we're not going to be using Direct2D
|
||||
// to access the contents of this texture client so we will always use D3D11.
|
||||
bool useD3D11 =
|
||||
windowsPlatform->GetContentBackendFor(LayersBackend::LAYERS_D3D11) == BackendType::DIRECT2D1_1 ||
|
||||
!NS_IsMainThread() ||
|
||||
(aFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT);
|
||||
|
||||
if (useD3D11) {
|
||||
return D3D11TextureData::Create(aSize, aFormat, aFlags);
|
||||
} else {
|
||||
return D3D10TextureData::Create(aSize, aFormat, aFlags);
|
||||
}
|
||||
return D3D11TextureData::Create(aSize, aFormat, aFlags);
|
||||
}
|
||||
|
||||
DXGITextureData*
|
||||
|
@ -507,59 +406,12 @@ D3D11TextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
|
|||
return D3D11TextureData::Create(mSize, mFormat, aAllocFlags);
|
||||
}
|
||||
|
||||
DXGITextureData*
|
||||
D3D10TextureData::Create(IntSize aSize, SurfaceFormat aFormat, TextureAllocationFlags aFlags)
|
||||
{
|
||||
RefPtr<ID3D10Texture2D> texture10;
|
||||
ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
|
||||
|
||||
CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
aSize.width, aSize.height, 1, 1,
|
||||
D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
|
||||
|
||||
newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED;
|
||||
|
||||
HRESULT hr = device->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(texture10));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize)))
|
||||
<< "[D3D10] 2 CreateTexture2D failure " << aSize << " Code: " << gfx::hexa(hr);
|
||||
return nullptr;
|
||||
}
|
||||
texture10->SetPrivateDataInterface(sD3D11TextureUsage,
|
||||
new TextureMemoryMeasurer(newDesc.Width * newDesc.Height * 4));
|
||||
|
||||
return new D3D10TextureData(texture10, aSize, aFormat,
|
||||
aFlags & ALLOC_CLEAR_BUFFER,
|
||||
aFlags & ALLOC_CLEAR_BUFFER_WHITE,
|
||||
false /* aIsForOutOfBandContent */);
|
||||
}
|
||||
|
||||
void
|
||||
D3D10TextureData::Deallocate(ISurfaceAllocator* aAllocator)
|
||||
{
|
||||
mTexture = nullptr;
|
||||
}
|
||||
|
||||
TextureData*
|
||||
D3D10TextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags) const
|
||||
{
|
||||
return D3D10TextureData::Create(mSize, mFormat, aAllocFlags);
|
||||
}
|
||||
|
||||
void
|
||||
D3D11TextureData::GetDXGIResource(IDXGIResource** aOutResource)
|
||||
{
|
||||
mTexture->QueryInterface(aOutResource);
|
||||
}
|
||||
|
||||
void
|
||||
D3D10TextureData::GetDXGIResource(IDXGIResource** aOutResource)
|
||||
{
|
||||
mTexture->QueryInterface(aOutResource);
|
||||
}
|
||||
|
||||
DXGIYCbCrTextureData*
|
||||
DXGIYCbCrTextureData::Create(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
|
@ -708,23 +560,6 @@ D3D11TextureData::BorrowDrawTarget()
|
|||
return result.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DrawTarget>
|
||||
D3D10TextureData::BorrowDrawTarget()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mDrawTarget && mTexture) {
|
||||
// This may return a null DrawTarget
|
||||
mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, mFormat);
|
||||
if (!mDrawTarget) {
|
||||
gfxCriticalNote << "Could not borrow DrawTarget (D3D10) " << (int)mFormat;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> result = mDrawTarget;
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
D3D11TextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
{
|
||||
|
@ -758,39 +593,6 @@ D3D11TextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
D3D10TextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
{
|
||||
RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
|
||||
|
||||
if (!srcSurf) {
|
||||
gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (D3D10).";
|
||||
return false;
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface sourceMap;
|
||||
if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) {
|
||||
gfxCriticalError() << "Failed to map source surface for UpdateFromSurface (D3D10).";
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<ID3D10Device> device;
|
||||
mTexture->GetDevice(getter_AddRefs(device));
|
||||
|
||||
D3D10_BOX box;
|
||||
box.front = 0;
|
||||
box.back = 1;
|
||||
box.top = box.left = 0;
|
||||
box.right = aSurface->GetSize().width;
|
||||
box.bottom = aSurface->GetSize().height;
|
||||
|
||||
device->UpdateSubresource(mTexture, 0, &box, sourceMap.mData, sourceMap.mStride, 0);
|
||||
|
||||
srcSurf->Unmap();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DXGITextureHostD3D11::DXGITextureHostD3D11(TextureFlags aFlags,
|
||||
const SurfaceDescriptorD3D10& aDescriptor)
|
||||
: TextureHost(aFlags)
|
||||
|
@ -1227,47 +1029,11 @@ SyncObjectD3D11::RegisterTexture(ID3D11Texture2D* aTexture)
|
|||
mD3D11SyncedTextures.push_back(aTexture);
|
||||
}
|
||||
|
||||
void
|
||||
SyncObjectD3D11::RegisterTexture(ID3D10Texture2D* aTexture)
|
||||
{
|
||||
mD3D10SyncedTextures.push_back(aTexture);
|
||||
}
|
||||
|
||||
void
|
||||
SyncObjectD3D11::FinalizeFrame()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (!mD3D10Texture && mD3D10SyncedTextures.size()) {
|
||||
ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = device->OpenSharedResource(mHandle, __uuidof(ID3D10Texture2D), (void**)(ID3D10Texture2D**)getter_AddRefs(mD3D10Texture));
|
||||
|
||||
if (FAILED(hr) || !mD3D10Texture) {
|
||||
gfxCriticalError() << "Failed to D3D10 OpenSharedResource for frame finalization: " << hexa(hr);
|
||||
|
||||
if (gfxWindowsPlatform::GetPlatform()->DidRenderingDeviceReset()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfxDevCrash(LogReason::D3D10FinalizeFrame) << "Without device reset: " << hexa(hr);
|
||||
}
|
||||
|
||||
// test QI
|
||||
RefPtr<IDXGIKeyedMutex> mutex;
|
||||
hr = mD3D10Texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
|
||||
|
||||
if (FAILED(hr) || !mutex) {
|
||||
// Leave both the critical error and MOZ_CRASH for now; the critical error lets
|
||||
// us "save" the hr value. We will probably eventuall replace this with gfxDevCrash.
|
||||
gfxCriticalError() << "Failed to get KeyedMutex (1): " << hexa(hr);
|
||||
MOZ_CRASH("GFX: Cannot get D3D10 KeyedMutex");
|
||||
}
|
||||
}
|
||||
|
||||
if (!mD3D11Texture && mD3D11SyncedTextures.size()) {
|
||||
ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice();
|
||||
|
||||
|
@ -1295,37 +1061,6 @@ SyncObjectD3D11::FinalizeFrame()
|
|||
}
|
||||
}
|
||||
|
||||
if (mD3D10SyncedTextures.size()) {
|
||||
RefPtr<IDXGIKeyedMutex> mutex;
|
||||
hr = mD3D10Texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
|
||||
hr = mutex->AcquireSync(0, 20000);
|
||||
|
||||
if (hr == WAIT_TIMEOUT) {
|
||||
if (gfxWindowsPlatform::GetPlatform()->DidRenderingDeviceReset()) {
|
||||
gfxWarning() << "AcquireSync timed out because of device reset.";
|
||||
return;
|
||||
}
|
||||
gfxDevCrash(LogReason::D3D10SyncLock) << "Timeout on the D3D10 sync lock";
|
||||
}
|
||||
|
||||
D3D10_BOX box;
|
||||
box.front = box.top = box.left = 0;
|
||||
box.back = box.bottom = box.right = 1;
|
||||
|
||||
ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto iter = mD3D10SyncedTextures.begin(); iter != mD3D10SyncedTextures.end(); iter++) {
|
||||
device->CopySubresourceRegion(mD3D10Texture, 0, 0, 0, 0, *iter, 0, &box);
|
||||
}
|
||||
|
||||
mutex->ReleaseSync(0);
|
||||
|
||||
mD3D10SyncedTextures.clear();
|
||||
}
|
||||
|
||||
if (mD3D11SyncedTextures.size()) {
|
||||
RefPtr<IDXGIKeyedMutex> mutex;
|
||||
hr = mD3D11Texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
|
||||
|
|
|
@ -109,45 +109,6 @@ CreateD3D11extureClientWithDevice(gfx::IntSize aSize, gfx::SurfaceFormat aFormat
|
|||
ID3D11Device* aDevice,
|
||||
ISurfaceAllocator* aAllocator);
|
||||
|
||||
|
||||
class D3D10TextureData : public DXGITextureData
|
||||
{
|
||||
public:
|
||||
static DXGITextureData*
|
||||
Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, TextureAllocationFlags aFlags);
|
||||
|
||||
virtual bool Lock(OpenMode aMode, FenceHandle*) override;
|
||||
|
||||
virtual void Unlock() override;
|
||||
|
||||
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
|
||||
|
||||
virtual TextureData*
|
||||
CreateSimilar(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags,
|
||||
TextureAllocationFlags aAllocFlags) const override;
|
||||
|
||||
// TODO - merge this with the FenceHandle API!
|
||||
virtual void SyncWithObject(SyncObject* aSync) override;
|
||||
|
||||
virtual bool ReadBack(TextureReadbackSink* aReadbackSinc) override;
|
||||
|
||||
virtual void Deallocate(ISurfaceAllocator* aAllocator) override;
|
||||
|
||||
~D3D10TextureData();
|
||||
protected:
|
||||
D3D10TextureData(ID3D10Texture2D* aTexture,
|
||||
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
bool aNeedsClear, bool aNeedsClearWhite,
|
||||
bool aIsForOutOfBandContent);
|
||||
|
||||
virtual void GetDXGIResource(IDXGIResource** aOutResource) override;
|
||||
|
||||
RefPtr<ID3D10Texture2D> mTexture;
|
||||
};
|
||||
|
||||
class DXGIYCbCrTextureData : public TextureData
|
||||
{
|
||||
public:
|
||||
|
@ -431,12 +392,9 @@ public:
|
|||
virtual SyncType GetSyncType() { return SyncType::D3D11; }
|
||||
|
||||
void RegisterTexture(ID3D11Texture2D* aTexture);
|
||||
void RegisterTexture(ID3D10Texture2D* aTexture);
|
||||
|
||||
private:
|
||||
RefPtr<ID3D11Texture2D> mD3D11Texture;
|
||||
RefPtr<ID3D10Texture2D> mD3D10Texture;
|
||||
std::vector<ID3D10Texture2D*> mD3D10SyncedTextures;
|
||||
std::vector<ID3D11Texture2D*> mD3D11SyncedTextures;
|
||||
SyncHandle mHandle;
|
||||
};
|
||||
|
|
|
@ -722,3 +722,18 @@ nsDeviceContext::UpdateAppUnitsForFullZoom()
|
|||
// adjust mFullZoom to reflect appunit rounding
|
||||
mFullZoom = float(mAppUnitsPerDevPixelAtUnitFullZoom) / mAppUnitsPerDevPixel;
|
||||
}
|
||||
|
||||
DesktopToLayoutDeviceScale
|
||||
nsDeviceContext::GetDesktopToDeviceScale()
|
||||
{
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
FindScreen(getter_AddRefs(screen));
|
||||
|
||||
if (screen) {
|
||||
double scale;
|
||||
screen->GetContentsScaleFactor(&scale);
|
||||
return DesktopToLayoutDeviceScale(scale);
|
||||
}
|
||||
|
||||
return DesktopToLayoutDeviceScale(1.0);
|
||||
}
|
||||
|
|
|
@ -251,6 +251,8 @@ public:
|
|||
*/
|
||||
bool IsPrinterSurface();
|
||||
|
||||
mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale();
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
~nsDeviceContext();
|
||||
|
|
|
@ -738,13 +738,24 @@ nsIntRegion nsRegion::ScaleToNearestPixels (float aScaleX, float aScaleY,
|
|||
nsIntRegion nsRegion::ScaleToOutsidePixels (float aScaleX, float aScaleY,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
nsIntRegion result;
|
||||
for (auto iter = RectIter(); !iter.Done(); iter.Next()) {
|
||||
mozilla::gfx::IntRect deviceRect =
|
||||
iter.Get().ScaleToOutsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
|
||||
result.Or(result, deviceRect);
|
||||
// make a copy of the region so that we can mutate it inplace
|
||||
nsRegion region = *this;
|
||||
int n;
|
||||
pixman_box32_t *boxes = pixman_region32_rectangles(®ion.mImpl, &n);
|
||||
boxes = pixman_region32_rectangles(®ion.mImpl, &n);
|
||||
for (int i=0; i<n; i++) {
|
||||
nsRect rect = BoxToRect(boxes[i]);
|
||||
mozilla::gfx::IntRect irect = rect.ScaleToOutsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
|
||||
boxes[i] = RectToBox(irect);
|
||||
}
|
||||
return result;
|
||||
|
||||
nsIntRegion iRegion;
|
||||
// clear out the initial pixman_region so that we can replace it below
|
||||
pixman_region32_fini(&iRegion.mImpl.mImpl);
|
||||
// This will union all of the rectangles and runs in about O(n lg(n))
|
||||
pixman_region32_init_rects(&iRegion.mImpl.mImpl, boxes, n);
|
||||
|
||||
return iRegion;
|
||||
}
|
||||
|
||||
nsIntRegion nsRegion::ScaleToInsidePixels (float aScaleX, float aScaleY,
|
||||
|
|
|
@ -594,7 +594,7 @@ RepeatOrStretchSurface(DrawTarget& aDT, SourceSurface* aSurface,
|
|||
|
||||
if ((!aDT.GetTransform().IsRectilinear() &&
|
||||
aDT.GetBackendType() != BackendType::CAIRO) ||
|
||||
(aDT.GetBackendType() == BackendType::DIRECT2D)) {
|
||||
(aDT.GetBackendType() == BackendType::DIRECT2D1_1)) {
|
||||
// Use stretching if possible, since it leads to less seams when the
|
||||
// destination is transformed. However, don't do this if we're using cairo,
|
||||
// because if cairo is using pixman it won't render anything for large
|
||||
|
|
|
@ -272,7 +272,7 @@ void CrashStatsLogForwarder::UpdateCrashReport()
|
|||
{
|
||||
std::stringstream message;
|
||||
for(LoggingRecord::iterator it = mBuffer.begin(); it != mBuffer.end(); ++it) {
|
||||
message << "|[" << Get<0>(*it) << "]" << Get<1>(*it) << " (t=" << Get<2>(*it) << ")";
|
||||
message << "|[" << Get<0>(*it) << "]" << Get<1>(*it) << " (t=" << Get<2>(*it) << ") ";
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
|
|
|
@ -212,6 +212,16 @@ private:
|
|||
WheelSmoothScrollMaxDurationMs, int32_t, 400);
|
||||
DECL_GFX_PREF(Live, "general.smoothScroll.mouseWheel.durationMinMS",
|
||||
WheelSmoothScrollMinDurationMs, int32_t, 200);
|
||||
DECL_GFX_PREF(Live, "general.smoothScroll.pages", PageSmoothScrollEnabled, bool, true);
|
||||
DECL_GFX_PREF(Live, "general.smoothScroll.pages.durationMaxMS",
|
||||
PageSmoothScrollMaxDurationMs, int32_t, 150);
|
||||
DECL_GFX_PREF(Live, "general.smoothScroll.pages.durationMinMS",
|
||||
PageSmoothScrollMinDurationMs, int32_t, 150);
|
||||
DECL_GFX_PREF(Live, "general.smoothScroll.pixels", PixelSmoothScrollEnabled, bool, true);
|
||||
DECL_GFX_PREF(Live, "general.smoothScroll.pixels.durationMaxMS",
|
||||
PixelSmoothScrollMaxDurationMs, int32_t, 150);
|
||||
DECL_GFX_PREF(Live, "general.smoothScroll.pixels.durationMinMS",
|
||||
PixelSmoothScrollMinDurationMs, int32_t, 150);
|
||||
DECL_GFX_PREF(Live, "general.smoothScroll.stopDecelerationWeighting",
|
||||
SmoothScrollStopDecelerationWeighting, float, 0.4f);
|
||||
|
||||
|
@ -242,8 +252,6 @@ private:
|
|||
|
||||
DECL_GFX_PREF(Once, "gfx.direct2d.disabled", Direct2DDisabled, bool, false);
|
||||
DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled", Direct2DForceEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.direct2d.use1_1", Direct2DUse1_1, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.direct2d.allow1_0", Direct2DAllow1_0, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false);
|
||||
DECL_GFX_PREF(Once, "gfx.e10s.hide-plugins-for-scroll", HidePluginsForScroll, bool, true);
|
||||
DECL_GFX_PREF(Once, "gfx.font_rendering.directwrite.force-enabled", DirectWriteFontRenderingForceEnabled, bool, false);
|
||||
|
@ -251,7 +259,7 @@ private:
|
|||
DECL_GFX_PREF(Live, "gfx.layerscope.enabled", LayerScopeEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.layerscope.port", LayerScopePort, int32_t, 23456);
|
||||
// Note that "gfx.logging.level" is defined in Logging.h
|
||||
DECL_GFX_PREF(Once, "gfx.logging.crash.length", GfxLoggingCrashLength, uint32_t, 6);
|
||||
DECL_GFX_PREF(Once, "gfx.logging.crash.length", GfxLoggingCrashLength, uint32_t, 16);
|
||||
// The maximums here are quite conservative, we can tighten them if problems show up.
|
||||
DECL_GFX_PREF(Once, "gfx.max-alloc-size", MaxAllocSize, int32_t, (int32_t)500000000);
|
||||
DECL_GFX_PREF(Once, "gfx.max-texture-size", MaxTextureSize, int32_t, (int32_t)32767);
|
||||
|
|
|
@ -422,8 +422,7 @@ CreateSamplingRestrictedDrawable(gfxDrawable* aDrawable,
|
|||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
DrawTarget* destDrawTarget = aContext->GetDrawTarget();
|
||||
if ((destDrawTarget->GetBackendType() == BackendType::DIRECT2D1_1) ||
|
||||
(destDrawTarget->GetBackendType() == BackendType::DIRECT2D)) {
|
||||
if (destDrawTarget->GetBackendType() == BackendType::DIRECT2D1_1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,12 +43,10 @@
|
|||
|
||||
#include "WinUtils.h"
|
||||
|
||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||
#include "gfxDWriteFontList.h"
|
||||
#include "gfxDWriteFonts.h"
|
||||
#include "gfxDWriteCommon.h"
|
||||
#include <dwrite.h>
|
||||
#endif
|
||||
|
||||
#include "gfxTextRun.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
|
@ -57,13 +55,11 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
#include <d3d10_1.h>
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
#include "nsMemory.h"
|
||||
#endif
|
||||
|
||||
#include <d3d11.h>
|
||||
|
||||
|
@ -114,14 +110,11 @@ DCFromDrawTarget::DCFromDrawTarget(DrawTarget& aDrawTarget)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
|
||||
static const char *kFeatureLevelPref =
|
||||
"gfx.direct3d.last_used_feature_level_idx";
|
||||
static const int kSupportedFeatureLevels[] =
|
||||
{ D3D10_FEATURE_LEVEL_10_1, D3D10_FEATURE_LEVEL_10_0 };
|
||||
|
||||
#endif
|
||||
|
||||
class GfxD2DVramReporter final : public nsIMemoryReporter
|
||||
{
|
||||
|
@ -166,16 +159,16 @@ NS_IMPL_ISUPPORTS(GfxD2DVramReporter, nsIMemoryReporter)
|
|||
class GPUAdapterReporter final : public nsIMemoryReporter
|
||||
{
|
||||
// Callers must Release the DXGIAdapter after use or risk mem-leak
|
||||
static bool GetDXGIAdapter(IDXGIAdapter **DXGIAdapter)
|
||||
static bool GetDXGIAdapter(IDXGIAdapter **aDXGIAdapter)
|
||||
{
|
||||
ID3D10Device1 *D2D10Device;
|
||||
IDXGIDevice *DXGIDevice;
|
||||
ID3D11Device *d3d11Device;
|
||||
IDXGIDevice *dxgiDevice;
|
||||
bool result = false;
|
||||
|
||||
if ((D2D10Device = mozilla::gfx::Factory::GetDirect3D10Device())) {
|
||||
if (D2D10Device->QueryInterface(__uuidof(IDXGIDevice), (void **)&DXGIDevice) == S_OK) {
|
||||
result = (DXGIDevice->GetAdapter(DXGIAdapter) == S_OK);
|
||||
DXGIDevice->Release();
|
||||
if ((d3d11Device = mozilla::gfx::Factory::GetDirect3D11Device())) {
|
||||
if (d3d11Device->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgiDevice) == S_OK) {
|
||||
result = (dxgiDevice->GetAdapter(aDXGIAdapter) == S_OK);
|
||||
dxgiDevice->Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -376,7 +369,6 @@ gfxWindowsPlatform::gfxWindowsPlatform()
|
|||
, mCompositorD3D11TextureSharingWorks(false)
|
||||
, mAcceleration(FeatureStatus::Unused)
|
||||
, mD3D11Status(FeatureStatus::Unused)
|
||||
, mD2DStatus(FeatureStatus::Unused)
|
||||
, mD2D1Status(FeatureStatus::Unused)
|
||||
{
|
||||
mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
|
||||
|
@ -411,7 +403,6 @@ gfxWindowsPlatform::gfxWindowsPlatform()
|
|||
gfxWindowsPlatform::~gfxWindowsPlatform()
|
||||
{
|
||||
mDeviceManager = nullptr;
|
||||
mD3D10Device = nullptr;
|
||||
mD3D11Device = nullptr;
|
||||
mD3D11ContentDevice = nullptr;
|
||||
mD3D11ImageBridgeDevice = nullptr;
|
||||
|
@ -489,9 +480,7 @@ gfxWindowsPlatform::HandleDeviceReset()
|
|||
|
||||
// Remove devices and adapters.
|
||||
ResetD3D11Devices();
|
||||
mD3D10Device = nullptr;
|
||||
mAdapter = nullptr;
|
||||
Factory::SetDirect3D10Device(nullptr);
|
||||
|
||||
// Reset local state. Note: we leave feature status variables as-is. They
|
||||
// will be recomputed by InitializeDevices().
|
||||
|
@ -519,17 +508,11 @@ gfxWindowsPlatform::UpdateBackendPrefs()
|
|||
uint32_t canvasMask = BackendTypeBit(SOFTWARE_BACKEND);
|
||||
uint32_t contentMask = BackendTypeBit(SOFTWARE_BACKEND);
|
||||
BackendType defaultBackend = SOFTWARE_BACKEND;
|
||||
if (GetD2DStatus() == FeatureStatus::Available) {
|
||||
if (GetD2D1Status() == FeatureStatus::Available) {
|
||||
mRenderMode = RENDER_DIRECT2D;
|
||||
canvasMask |= BackendTypeBit(BackendType::DIRECT2D);
|
||||
contentMask |= BackendTypeBit(BackendType::DIRECT2D);
|
||||
if (GetD2D1Status() == FeatureStatus::Available) {
|
||||
contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
|
||||
canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
|
||||
defaultBackend = BackendType::DIRECT2D1_1;
|
||||
} else {
|
||||
defaultBackend = BackendType::DIRECT2D;
|
||||
}
|
||||
contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
|
||||
canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
|
||||
defaultBackend = BackendType::DIRECT2D1_1;
|
||||
} else {
|
||||
mRenderMode = RENDER_GDI;
|
||||
canvasMask |= BackendTypeBit(BackendType::SKIA);
|
||||
|
@ -571,129 +554,11 @@ gfxWindowsPlatform::GetContentBackendFor(mozilla::layers::LayersBackend aLayers)
|
|||
return SOFTWARE_BACKEND;
|
||||
}
|
||||
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
HRESULT
|
||||
gfxWindowsPlatform::CreateDevice(RefPtr<IDXGIAdapter1> &adapter1,
|
||||
int featureLevelIndex)
|
||||
{
|
||||
nsModuleHandle d3d10module(LoadLibrarySystem32(L"d3d10_1.dll"));
|
||||
if (!d3d10module)
|
||||
return E_FAIL;
|
||||
decltype(D3D10CreateDevice1)* createD3DDevice =
|
||||
(decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module, "D3D10CreateDevice1");
|
||||
if (!createD3DDevice)
|
||||
return E_FAIL;
|
||||
|
||||
ID3D10Device1* device = nullptr;
|
||||
HRESULT hr =
|
||||
createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
|
||||
#ifdef DEBUG
|
||||
// This isn't set because of bug 1078411
|
||||
// D3D10_CREATE_DEVICE_DEBUG |
|
||||
#endif
|
||||
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
|
||||
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
||||
static_cast<D3D10_FEATURE_LEVEL1>(kSupportedFeatureLevels[featureLevelIndex]),
|
||||
D3D10_1_SDK_VERSION, &device);
|
||||
|
||||
// If we fail here, the DirectX version or video card probably
|
||||
// changed. We previously could use 10.1 but now we can't
|
||||
// anymore. Revert back to doing a 10.0 check first before
|
||||
// the 10.1 check.
|
||||
if (device) {
|
||||
mD3D10Device = device;
|
||||
|
||||
// Leak the module while the D3D 10 device is being used.
|
||||
d3d10module.disown();
|
||||
|
||||
// Setup a pref for future launch optimizaitons when in main process.
|
||||
if (XRE_IsParentProcess()) {
|
||||
Preferences::SetInt(kFeatureLevelPref, featureLevelIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return device ? S_OK : hr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
|
||||
{
|
||||
if ((!Factory::SupportsD2D1() || !gfxPrefs::Direct2DUse1_1()) && !gfxPrefs::Direct2DAllow1_0()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
if (mD3D10Device) {
|
||||
if (SUCCEEDED(mD3D10Device->GetDeviceRemovedReason())) {
|
||||
return;
|
||||
}
|
||||
mD3D10Device = nullptr;
|
||||
|
||||
// Surface cache needs to be invalidated since it may contain vector
|
||||
// images rendered with our old, broken D2D device.
|
||||
SurfaceCache::DiscardAll();
|
||||
}
|
||||
|
||||
mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce);
|
||||
|
||||
int supportedFeatureLevelsCount = ArrayLength(kSupportedFeatureLevels);
|
||||
|
||||
RefPtr<IDXGIAdapter1> adapter1 = GetDXGIAdapter();
|
||||
|
||||
if (!adapter1) {
|
||||
// Unable to create adapter, abort acceleration.
|
||||
return;
|
||||
}
|
||||
|
||||
// It takes a lot of time (5-10% of startup time or ~100ms) to do both
|
||||
// a createD3DDevice on D3D10_FEATURE_LEVEL_10_0. We therefore store
|
||||
// the last used feature level to go direct to that.
|
||||
int featureLevelIndex = Preferences::GetInt(kFeatureLevelPref, 0);
|
||||
if (featureLevelIndex >= supportedFeatureLevelsCount || featureLevelIndex < 0)
|
||||
featureLevelIndex = 0;
|
||||
|
||||
// Start with the last used feature level, and move to lower DX versions
|
||||
// until we find one that works.
|
||||
HRESULT hr = E_FAIL;
|
||||
for (int i = featureLevelIndex; i < supportedFeatureLevelsCount; i++) {
|
||||
hr = CreateDevice(adapter1, i);
|
||||
// If it succeeded we found the first available feature level
|
||||
if (SUCCEEDED(hr))
|
||||
break;
|
||||
}
|
||||
|
||||
// If we succeeded in creating a device, try for a newer device
|
||||
// that we haven't tried yet.
|
||||
if (SUCCEEDED(hr)) {
|
||||
for (int i = featureLevelIndex - 1; i >= 0; i--) {
|
||||
hr = CreateDevice(adapter1, i);
|
||||
// If it failed then we don't have new hardware
|
||||
if (FAILED(hr)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mD3D10Device) {
|
||||
reporter.SetSuccessful();
|
||||
mozilla::gfx::Factory::SetDirect3D10Device(mD3D10Device);
|
||||
}
|
||||
|
||||
ScopedGfxFeatureReporter reporter1_1("D2D1.1V");
|
||||
|
||||
if (Factory::SupportsD2D1()) {
|
||||
reporter1_1.SetSuccessful();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
gfxPlatformFontList*
|
||||
gfxWindowsPlatform::CreatePlatformFontList()
|
||||
{
|
||||
gfxPlatformFontList *pfl;
|
||||
|
||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||
// bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd
|
||||
// crashers so blacklist them altogether
|
||||
if (IsNotWin7PreRTM() && GetDWriteFactory()) {
|
||||
|
@ -707,7 +572,7 @@ gfxWindowsPlatform::CreatePlatformFontList()
|
|||
gfxPlatformFontList::Shutdown();
|
||||
DisableD2D();
|
||||
}
|
||||
#endif
|
||||
|
||||
pfl = new gfxGDIFontList();
|
||||
|
||||
if (NS_SUCCEEDED(pfl->InitFontList())) {
|
||||
|
@ -727,10 +592,8 @@ gfxWindowsPlatform::CreatePlatformFontList()
|
|||
void
|
||||
gfxWindowsPlatform::DisableD2D()
|
||||
{
|
||||
mD2DStatus = FeatureStatus::Failed;
|
||||
mD2D1Status = FeatureStatus::Failed;
|
||||
Factory::SetDirect3D11Device(nullptr);
|
||||
Factory::SetDirect3D10Device(nullptr);
|
||||
UpdateBackendPrefs();
|
||||
}
|
||||
|
||||
|
@ -1178,12 +1041,6 @@ gfxWindowsPlatform::DidRenderingDeviceReset(DeviceResetReason* aResetReason)
|
|||
return true;
|
||||
}
|
||||
}
|
||||
if (GetD3D10Device()) {
|
||||
HRESULT hr = GetD3D10Device()->GetDeviceRemovedReason();
|
||||
if (IsDeviceReset(hr, aResetReason)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (XRE_IsParentProcess() && gfxPrefs::DeviceResetForTesting()) {
|
||||
TestDeviceReset((DeviceResetReason)gfxPrefs::DeviceResetForTesting());
|
||||
if (aResetReason) {
|
||||
|
@ -1447,7 +1304,6 @@ gfxWindowsPlatform::FontsPrefsChanged(const char *aPref)
|
|||
void
|
||||
gfxWindowsPlatform::SetupClearTypeParams()
|
||||
{
|
||||
#if CAIRO_HAS_DWRITE_FONT
|
||||
if (GetDWriteFactory()) {
|
||||
// any missing prefs will default to invalid (-1) and be ignored;
|
||||
// out-of-range values will also be ignored
|
||||
|
@ -1555,7 +1411,6 @@ gfxWindowsPlatform::SetupClearTypeParams()
|
|||
dwriteGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
|
||||
getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC]));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2417,7 +2272,7 @@ gfxWindowsPlatform::InitializeDevices()
|
|||
// Usually we want D2D in order to use DWrite, but if the users have it
|
||||
// forced, we'll let them have it, as unsupported configuration.
|
||||
if (gfxPrefs::DirectWriteFontRenderingForceEnabled() &&
|
||||
IsFeatureStatusFailure(mD2DStatus) &&
|
||||
IsFeatureStatusFailure(mD2D1Status) &&
|
||||
!mDWriteFactory) {
|
||||
gfxCriticalNote << "Attempting DWrite without D2D support";
|
||||
InitDWriteSupport();
|
||||
|
@ -2583,17 +2438,11 @@ IsD2DBlacklisted()
|
|||
// not change after a TDR (like the OS version), we could find a driver change
|
||||
// that runs us into the blacklist.
|
||||
FeatureStatus
|
||||
gfxWindowsPlatform::CheckD2DSupport()
|
||||
gfxWindowsPlatform::CheckD2D1Support()
|
||||
{
|
||||
// Don't revive D2D support after a failure.
|
||||
if (IsFeatureStatusFailure(mD2DStatus)) {
|
||||
return mD2DStatus;
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
return GetParentDevicePrefs().useD2D()
|
||||
? FeatureStatus::Available
|
||||
: FeatureStatus::Blocked;
|
||||
// Don't revive D2D1 support after a failure.
|
||||
if (IsFeatureStatusFailure(mD2D1Status)) {
|
||||
return mD2D1Status;
|
||||
}
|
||||
|
||||
if (!gfxPrefs::Direct2DForceEnabled() && IsD2DBlacklisted()) {
|
||||
|
@ -2617,70 +2466,38 @@ gfxWindowsPlatform::CheckD2DSupport()
|
|||
if (mIsWARP && !gfxPrefs::LayersD3D11ForceWARP()) {
|
||||
return FeatureStatus::Blocked;
|
||||
}
|
||||
|
||||
if (!Factory::SupportsD2D1()) {
|
||||
return FeatureStatus::Unavailable;
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
return GetParentDevicePrefs().useD2D1()
|
||||
? FeatureStatus::Available
|
||||
: FeatureStatus::Blocked;
|
||||
}
|
||||
|
||||
return FeatureStatus::Available;
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::InitializeD2D()
|
||||
{
|
||||
mD2DStatus = CheckD2DSupport();
|
||||
if (IsFeatureStatusFailure(mD2DStatus)) {
|
||||
ScopedGfxFeatureReporter d2d1_1("D2D1.1");
|
||||
|
||||
mD2D1Status = CheckD2D1Support();
|
||||
if (IsFeatureStatusFailure(mD2D1Status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mCompositorD3D11TextureSharingWorks) {
|
||||
mD2DStatus = FeatureStatus::Failed;
|
||||
mD2D1Status = FeatureStatus::Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
// Using Direct2D depends on DWrite support.
|
||||
if (!mDWriteFactory && !InitDWriteSupport()) {
|
||||
mD2DStatus = FeatureStatus::Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize D2D 1.1.
|
||||
InitializeD2D1();
|
||||
|
||||
// Initialize D2D 1.0.
|
||||
VerifyD2DDevice(gfxPrefs::Direct2DForceEnabled());
|
||||
if (!mD3D10Device) {
|
||||
mDWriteFactory = nullptr;
|
||||
mD2DStatus = FeatureStatus::Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
mD2DStatus = FeatureStatus::Available;
|
||||
}
|
||||
|
||||
FeatureStatus
|
||||
gfxWindowsPlatform::CheckD2D1Support()
|
||||
{
|
||||
// Don't revive D2D1 support after a failure.
|
||||
if (IsFeatureStatusFailure(mD2D1Status)) {
|
||||
return mD2D1Status;
|
||||
}
|
||||
if (!Factory::SupportsD2D1()) {
|
||||
return FeatureStatus::Unavailable;
|
||||
}
|
||||
if (XRE_IsContentProcess()) {
|
||||
return GetParentDevicePrefs().useD2D1()
|
||||
? FeatureStatus::Available
|
||||
: FeatureStatus::Blocked;
|
||||
}
|
||||
if (!gfxPrefs::Direct2DUse1_1()) {
|
||||
return FeatureStatus::Disabled;
|
||||
}
|
||||
return FeatureStatus::Available;
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::InitializeD2D1()
|
||||
{
|
||||
ScopedGfxFeatureReporter d2d1_1("D2D1.1");
|
||||
|
||||
mD2D1Status = CheckD2D1Support();
|
||||
if (IsFeatureStatusFailure(mD2D1Status)) {
|
||||
mD2D1Status = FeatureStatus::Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2693,6 +2510,8 @@ gfxWindowsPlatform::InitializeD2D1()
|
|||
Factory::SetDirect3D11Device(mD3D11ContentDevice);
|
||||
|
||||
d2d1_1.SetSuccessful();
|
||||
|
||||
mD2D1Status = FeatureStatus::Available;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -3051,15 +2870,6 @@ gfxWindowsPlatform::GetD3D11Status() const
|
|||
return mD3D11Status;
|
||||
}
|
||||
|
||||
FeatureStatus
|
||||
gfxWindowsPlatform::GetD2DStatus() const
|
||||
{
|
||||
if (GetD3D11Status() != FeatureStatus::Available) {
|
||||
return FeatureStatus::Unavailable;
|
||||
}
|
||||
return mD2DStatus;
|
||||
}
|
||||
|
||||
FeatureStatus
|
||||
gfxWindowsPlatform::GetD2D1Status() const
|
||||
{
|
||||
|
@ -3096,7 +2906,6 @@ gfxWindowsPlatform::GetDeviceInitData(DeviceInitData* aOut)
|
|||
aOut->useD3D11ImageBridge() = !!mD3D11ImageBridgeDevice;
|
||||
aOut->d3d11TextureSharingWorks() = mCompositorD3D11TextureSharingWorks;
|
||||
aOut->useD3D11WARP() = mIsWARP;
|
||||
aOut->useD2D() = (GetD2DStatus() == FeatureStatus::Available);
|
||||
aOut->useD2D1() = (GetD2D1Status() == FeatureStatus::Available);
|
||||
|
||||
if (mD3D11Device) {
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
#include "gfxFontUtils.h"
|
||||
#include "gfxWindowsSurface.h"
|
||||
#include "gfxFont.h"
|
||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||
#include "gfxDWriteFonts.h"
|
||||
#endif
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxTelemetry.h"
|
||||
#include "gfxTypes.h"
|
||||
|
@ -33,9 +31,7 @@
|
|||
#include <windows.h>
|
||||
#include <objbase.h>
|
||||
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
#include <dxgi.h>
|
||||
#endif
|
||||
|
||||
// This header is available in the June 2010 SDK and in the Win8 SDK
|
||||
#include <d3dcommon.h>
|
||||
|
@ -163,10 +159,6 @@ public:
|
|||
*/
|
||||
void VerifyD2DDevice(bool aAttemptForce);
|
||||
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
HRESULT CreateDevice(RefPtr<IDXGIAdapter1> &adapter1, int featureLevelIndex);
|
||||
#endif
|
||||
|
||||
nsresult GetFontList(nsIAtom *aLangGroup,
|
||||
const nsACString& aGenericFamily,
|
||||
nsTArray<nsString>& aListOfFonts) override;
|
||||
|
@ -230,20 +222,16 @@ public:
|
|||
|
||||
void SetupClearTypeParams();
|
||||
|
||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||
IDWriteFactory *GetDWriteFactory() { return mDWriteFactory; }
|
||||
inline bool DWriteEnabled() { return !!mDWriteFactory; }
|
||||
inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; }
|
||||
|
||||
IDWriteRenderingParams *GetRenderingParams(TextRenderingMode aRenderMode)
|
||||
{ return mRenderingParams[aRenderMode]; }
|
||||
#else
|
||||
inline bool DWriteEnabled() { return false; }
|
||||
#endif
|
||||
|
||||
void OnDeviceManagerDestroy(mozilla::layers::DeviceManagerD3D9* aDeviceManager);
|
||||
mozilla::layers::DeviceManagerD3D9* GetD3D9DeviceManager();
|
||||
IDirect3DDevice9* GetD3D9Device();
|
||||
ID3D10Device1 *GetD3D10Device() { return mD3D10Device; }
|
||||
ID3D11Device *GetD3D11Device();
|
||||
ID3D11Device *GetD3D11ContentDevice();
|
||||
ID3D11Device* GetD3D11DeviceForCurrentThread();
|
||||
|
@ -281,7 +269,6 @@ public:
|
|||
// initialization has not been attempted, this returns
|
||||
// FeatureStatus::Unused.
|
||||
mozilla::gfx::FeatureStatus GetD3D11Status() const;
|
||||
mozilla::gfx::FeatureStatus GetD2DStatus() const;
|
||||
mozilla::gfx::FeatureStatus GetD2D1Status() const;
|
||||
unsigned GetD3D11Version();
|
||||
|
||||
|
@ -319,14 +306,12 @@ private:
|
|||
void InitializeDevices();
|
||||
void InitializeD3D11();
|
||||
void InitializeD2D();
|
||||
void InitializeD2D1();
|
||||
bool InitDWriteSupport();
|
||||
|
||||
void DisableD2D();
|
||||
|
||||
mozilla::gfx::FeatureStatus CheckAccelerationSupport();
|
||||
mozilla::gfx::FeatureStatus CheckD3D11Support(bool* aCanUseHardware);
|
||||
mozilla::gfx::FeatureStatus CheckD2DSupport();
|
||||
mozilla::gfx::FeatureStatus CheckD2D1Support();
|
||||
|
||||
mozilla::gfx::FeatureStatus AttemptD3D11DeviceCreation();
|
||||
|
@ -352,14 +337,12 @@ private:
|
|||
IDXGIAdapter1 *GetDXGIAdapter();
|
||||
bool IsDeviceReset(HRESULT hr, DeviceResetReason* aReason);
|
||||
|
||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||
RefPtr<IDWriteFactory> mDWriteFactory;
|
||||
RefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
|
||||
DWRITE_MEASURING_MODE mMeasuringMode;
|
||||
#endif
|
||||
|
||||
RefPtr<IDXGIAdapter1> mAdapter;
|
||||
RefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager;
|
||||
RefPtr<ID3D10Device1> mD3D10Device;
|
||||
RefPtr<ID3D11Device> mD3D11Device;
|
||||
RefPtr<ID3D11Device> mD3D11ContentDevice;
|
||||
RefPtr<ID3D11Device> mD3D11ImageBridgeDevice;
|
||||
|
@ -374,7 +357,6 @@ private:
|
|||
// accessors instead.
|
||||
mozilla::gfx::FeatureStatus mAcceleration;
|
||||
mozilla::gfx::FeatureStatus mD3D11Status;
|
||||
mozilla::gfx::FeatureStatus mD2DStatus;
|
||||
mozilla::gfx::FeatureStatus mD2D1Status;
|
||||
|
||||
nsTArray<D3D_FEATURE_LEVEL> mFeatureLevels;
|
||||
|
|
|
@ -450,6 +450,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
|||
case State::BITFIELDS: return ReadBitfields(aData, aLength);
|
||||
case State::COLOR_TABLE: return ReadColorTable(aData, aLength);
|
||||
case State::GAP: return SkipGap();
|
||||
case State::AFTER_GAP: return AfterGap();
|
||||
case State::PIXEL_ROW: return ReadPixelRow(aData);
|
||||
case State::RLE_SEGMENT: return ReadRLESegment(aData);
|
||||
case State::RLE_DELTA: return ReadRLEDelta(aData);
|
||||
|
@ -719,12 +720,19 @@ nsBMPDecoder::ReadColorTable(const char* aData, size_t aLength)
|
|||
PostDataError();
|
||||
return Transition::TerminateFailure();
|
||||
}
|
||||
|
||||
uint32_t gapLength = mH.mDataOffset - mPreGapLength;
|
||||
return Transition::To(State::GAP, gapLength);
|
||||
return Transition::ToUnbuffered(State::AFTER_GAP, State::GAP, gapLength);
|
||||
}
|
||||
|
||||
LexerTransition<nsBMPDecoder::State>
|
||||
nsBMPDecoder::SkipGap()
|
||||
{
|
||||
return Transition::ContinueUnbuffered(State::GAP);
|
||||
}
|
||||
|
||||
LexerTransition<nsBMPDecoder::State>
|
||||
nsBMPDecoder::AfterGap()
|
||||
{
|
||||
// If there are no pixels we can stop.
|
||||
//
|
||||
|
|
|
@ -165,6 +165,7 @@ private:
|
|||
BITFIELDS,
|
||||
COLOR_TABLE,
|
||||
GAP,
|
||||
AFTER_GAP,
|
||||
PIXEL_ROW,
|
||||
RLE_SEGMENT,
|
||||
RLE_DELTA,
|
||||
|
@ -194,6 +195,7 @@ private:
|
|||
LexerTransition<State> ReadBitfields(const char* aData, size_t aLength);
|
||||
LexerTransition<State> ReadColorTable(const char* aData, size_t aLength);
|
||||
LexerTransition<State> SkipGap();
|
||||
LexerTransition<State> AfterGap();
|
||||
LexerTransition<State> ReadPixelRow(const char* aData);
|
||||
LexerTransition<State> ReadRLESegment(const char* aData);
|
||||
LexerTransition<State> ReadRLEDelta(const char* aData);
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 68 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 68 B |
|
@ -6,3 +6,11 @@ include bmp-8bpp/reftest.list
|
|||
include bmp-24bpp/reftest.list
|
||||
include bmp-corrupted/reftest.list
|
||||
include bmpsuite/reftest.list
|
||||
|
||||
# Two bmp files where the offset to the start of the image data in the file
|
||||
# is past the end of the file. In 1240629-1.bmp the offset us uint32_max,
|
||||
# so we are testing that we don't try to allocate a buffer that size (and
|
||||
# fail on 32 bit platforms) and declare the image in error state. If in the
|
||||
# future we decide that such bmps (offset past the end of the file) are
|
||||
# invalid the test will still pass, but won't be testing much.
|
||||
== 1240629-1.bmp 1240629-2.bmp
|
||||
|
|
|
@ -618,30 +618,6 @@ class DispatchWrapper
|
|||
}
|
||||
};
|
||||
|
||||
inline RootLists&
|
||||
RootListsForRootingContext(JSContext* cx)
|
||||
{
|
||||
return ContextFriendFields::get(cx)->roots;
|
||||
}
|
||||
|
||||
inline RootLists&
|
||||
RootListsForRootingContext(js::ContextFriendFields* cx)
|
||||
{
|
||||
return cx->roots;
|
||||
}
|
||||
|
||||
inline RootLists&
|
||||
RootListsForRootingContext(JSRuntime* rt)
|
||||
{
|
||||
return PerThreadDataFriendFields::getMainThread(rt)->roots;
|
||||
}
|
||||
|
||||
inline RootLists&
|
||||
RootListsForRootingContext(js::PerThreadDataFriendFields* pt)
|
||||
{
|
||||
return pt->roots;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
namespace JS {
|
||||
|
@ -664,19 +640,26 @@ class MOZ_RAII Rooted : public js::RootedBase<T>
|
|||
*stack = reinterpret_cast<Rooted<void*>*>(this);
|
||||
}
|
||||
|
||||
js::RootLists& rootLists(js::ContextFriendFields* cx) { return cx->roots; }
|
||||
js::RootLists& rootLists(JSContext* cx) { return js::ContextFriendFields::get(cx)->roots; }
|
||||
js::RootLists& rootLists(js::PerThreadDataFriendFields* pt) { return pt->roots; }
|
||||
js::RootLists& rootLists(JSRuntime* rt) {
|
||||
return js::PerThreadDataFriendFields::getMainThread(rt)->roots;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename RootingContext>
|
||||
explicit Rooted(const RootingContext& cx)
|
||||
: ptr(js::GCPolicy<T>::initial())
|
||||
{
|
||||
registerWithRootLists(js::RootListsForRootingContext(cx));
|
||||
registerWithRootLists(rootLists(cx));
|
||||
}
|
||||
|
||||
template <typename RootingContext, typename S>
|
||||
Rooted(const RootingContext& cx, S&& initial)
|
||||
: ptr(mozilla::Forward<S>(initial))
|
||||
{
|
||||
registerWithRootLists(js::RootListsForRootingContext(cx));
|
||||
registerWithRootLists(rootLists(cx));
|
||||
}
|
||||
|
||||
~Rooted() {
|
||||
|
@ -976,6 +959,15 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
|
|||
roots.heapRoots_[kind].insertBack(reinterpret_cast<JS::PersistentRooted<void*>*>(this));
|
||||
}
|
||||
|
||||
js::RootLists& rootLists(js::PerThreadDataFriendFields* pt) { return pt->roots; }
|
||||
js::RootLists& rootLists(JSRuntime* rt) {
|
||||
return js::PerThreadDataFriendFields::getMainThread(rt)->roots;
|
||||
}
|
||||
js::RootLists& rootLists(JSContext* cx) { return rootLists(js::GetRuntime(cx)); }
|
||||
js::RootLists& rootLists(js::ContextFriendFields* cx) {
|
||||
return rootLists(reinterpret_cast<JSContext*>(cx));
|
||||
}
|
||||
|
||||
public:
|
||||
PersistentRooted() : ptr(js::GCPolicy<T>::initial()) {}
|
||||
|
||||
|
@ -983,14 +975,14 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
|
|||
explicit PersistentRooted(const RootingContext& cx)
|
||||
: ptr(js::GCPolicy<T>::initial())
|
||||
{
|
||||
registerWithRootLists(js::RootListsForRootingContext(cx));
|
||||
registerWithRootLists(rootLists(cx));
|
||||
}
|
||||
|
||||
template <typename RootingContext, typename U>
|
||||
PersistentRooted(const RootingContext& cx, U&& initial)
|
||||
: ptr(mozilla::Forward<U>(initial))
|
||||
{
|
||||
registerWithRootLists(js::RootListsForRootingContext(cx));
|
||||
registerWithRootLists(rootLists(cx));
|
||||
}
|
||||
|
||||
PersistentRooted(const PersistentRooted& rhs)
|
||||
|
@ -1020,7 +1012,7 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
|
|||
template <typename RootingContext, typename U>
|
||||
void init(const RootingContext& cx, U&& initial) {
|
||||
ptr = mozilla::Forward<U>(initial);
|
||||
registerWithRootLists(js::RootListsForRootingContext(cx));
|
||||
registerWithRootLists(rootLists(cx));
|
||||
}
|
||||
|
||||
void reset() {
|
||||
|
|
|
@ -844,7 +844,8 @@ class Edge {
|
|||
// false as the wantNames parameter.
|
||||
//
|
||||
// The storage is owned by this Edge, and will be freed when this Edge is
|
||||
// destructed.
|
||||
// destructed. You may take ownership of the name by `mozilla::Move`ing it
|
||||
// out of the edge; it is just a UniquePtr.
|
||||
//
|
||||
// (In real life we'll want a better representation for names, to avoid
|
||||
// creating tons of strings when the names follow a pattern; and we'll need
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче