Merge m-c to f-t

This commit is contained in:
Phil Ringnalda 2016-02-13 19:26:30 -08:00
commit edbecc1e27
230 changed files with 2717 additions and 6777 deletions

View File

@ -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;"

View File

@ -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

View File

@ -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);
},

View File

@ -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.

View File

@ -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();
}

View File

@ -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">

View File

@ -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;
}

View File

@ -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();">

View File

@ -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!");

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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,

View File

@ -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);
}
}
}

View File

@ -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)

View File

@ -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);

View File

@ -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 ====================
// ======================================================

View File

@ -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)

View File

@ -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"

View File

@ -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();

View File

@ -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)
{

View File

@ -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

View File

@ -106,7 +106,6 @@ WebGLContext::WebGLContext()
, mMaxFetchedVertices(0)
, mMaxFetchedInstances(0)
, mBypassShaderValidation(false)
, mGLMaxSamples(1)
, mNeedsFakeNoAlpha(false)
, mNeedsFakeNoDepth(false)
, mNeedsFakeNoStencil(false)

View File

@ -1114,7 +1114,6 @@ protected:
int32_t mGLMaxVertexUniformVectors;
uint32_t mGLMaxTransformFeedbackSeparateAttribs;
GLuint mGLMaxUniformBufferBindings;
GLsizei mGLMaxSamples;
// What is supported:
uint32_t mGLMaxColorAttachments;

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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());

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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 {

View File

@ -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)
{

View File

@ -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);

View File

@ -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());

View File

@ -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());

View File

@ -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)

View File

@ -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;

View File

@ -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() { }
};

View File

@ -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)

View File

@ -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();

View File

@ -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__);
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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>

View File

@ -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;

View File

@ -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)
{

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
}
}
}

View File

@ -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_ */

View File

@ -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;
}
}
}
}

View File

@ -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_ */

View File

@ -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,

View File

@ -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

View File

@ -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) );

View File

@ -206,7 +206,7 @@ public:
GLsizei Samples() const {
if (!mDraw)
return 1;
return 0;
return mDraw->mSamples;
}

View File

@ -19,7 +19,6 @@ struct DeviceInitData
bool useD3D11WARP;
bool useD3D11ImageBridge;
bool d3d11TextureSharingWorks;
bool useD2D;
bool useD2D1;
DxgiAdapterDesc adapter;
};

View File

@ -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;

View File

@ -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;
}

View File

@ -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 =

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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;
};

View File

@ -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

View File

@ -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)

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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));

View File

@ -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;
};

View File

@ -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);
}

View File

@ -251,6 +251,8 @@ public:
*/
bool IsPrinterSurface();
mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale();
private:
// Private destructor, to discourage deletion outside of Release():
~nsDeviceContext();

View File

@ -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(&region.mImpl, &n);
boxes = pixman_region32_rectangles(&region.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,

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;

View File

@ -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.
//

View File

@ -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);

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View File

@ -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

View File

@ -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() {

View File

@ -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

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