зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
Коммит
c2709dc7e9
|
@ -195,7 +195,7 @@ class UrlbarInput {
|
|||
// Private methods below.
|
||||
|
||||
_updateTextOverflow() {
|
||||
if (!this._inOverflow) {
|
||||
if (!this._overflowing) {
|
||||
this.removeAttribute("textoverflow");
|
||||
return;
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ class UrlbarInput {
|
|||
this.window.promiseDocumentFlushed(() => {
|
||||
// Check overflow again to ensure it didn't change in the meantime.
|
||||
let input = this.inputField;
|
||||
if (input && this._inOverflow) {
|
||||
if (input && this._overflowing) {
|
||||
let side = input.scrollLeft &&
|
||||
input.scrollLeft == input.scrollLeftMax ? "start" : "end";
|
||||
this.setAttribute("textoverflow", side);
|
||||
|
@ -212,7 +212,7 @@ class UrlbarInput {
|
|||
}
|
||||
|
||||
_updateUrlTooltip() {
|
||||
if (this.focused || !this._inOverflow) {
|
||||
if (this.focused || !this._overflowing) {
|
||||
this.inputField.removeAttribute("title");
|
||||
} else {
|
||||
this.inputField.setAttribute("title", this.value);
|
||||
|
@ -392,7 +392,7 @@ class UrlbarInput {
|
|||
if (targetIsPlaceholder) {
|
||||
return;
|
||||
}
|
||||
this._inOverflow = true;
|
||||
this._overflowing = true;
|
||||
this._updateTextOverflow();
|
||||
}
|
||||
|
||||
|
@ -404,7 +404,7 @@ class UrlbarInput {
|
|||
if (targetIsPlaceholder) {
|
||||
return;
|
||||
}
|
||||
this._inOverflow = false;
|
||||
this._overflowing = false;
|
||||
|
||||
this._updateTextOverflow();
|
||||
|
||||
|
|
|
@ -35,10 +35,17 @@ function sortWithClones(requests, sorter, a, b) {
|
|||
return sorter(a, b);
|
||||
}
|
||||
|
||||
const getFilterFn = createSelector(
|
||||
/**
|
||||
* Take clones into account when filtering. If a request is
|
||||
* a clone, it's not filtered out.
|
||||
*/
|
||||
const getFilterWithCloneFn = createSelector(
|
||||
state => state.filters,
|
||||
filters => r => {
|
||||
const matchesType = Object.keys(filters.requestFilterTypes).some(filter => {
|
||||
if (r.id.endsWith("-clone")) {
|
||||
return true;
|
||||
}
|
||||
return filters.requestFilterTypes[filter] && Filters[filter] && Filters[filter](r);
|
||||
});
|
||||
return matchesType && isFreetextMatch(r, filters.requestFilterText);
|
||||
|
@ -78,7 +85,7 @@ const getSortedRequests = createSelector(
|
|||
|
||||
const getDisplayedRequests = createSelector(
|
||||
state => state.requests,
|
||||
getFilterFn,
|
||||
getFilterWithCloneFn,
|
||||
getSortFn,
|
||||
({ requests }, filterFn, sortFn) => {
|
||||
const arr = [...requests.values()].filter(filterFn).sort(sortFn);
|
||||
|
|
|
@ -120,6 +120,7 @@ subsuite = clipboard
|
|||
skip-if = (os == 'mac') # Bug 1479782
|
||||
[browser_net_header-docs.js]
|
||||
[browser_net_edit_resend_caret.js]
|
||||
[browser_net_edit_resend_with_filtering.js]
|
||||
[browser_net_filter-01.js]
|
||||
[browser_net_filter-02.js]
|
||||
[browser_net_filter-03.js]
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if resending a XHR request while filtering XHR displays
|
||||
* the correct requests
|
||||
*/
|
||||
add_task(async function() {
|
||||
const { tab, monitor } = await initNetMonitor(POST_RAW_URL);
|
||||
|
||||
const { document, store, windowRequire, parent } = monitor.panelWin;
|
||||
const parentDocument = parent.document;
|
||||
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
store.dispatch(Actions.batchEnable(false));
|
||||
|
||||
// Execute XHR request and filter by XHR
|
||||
await performRequests(monitor, tab, 1);
|
||||
document.querySelector(".requests-list-filter-xhr-button").click();
|
||||
|
||||
// Confirm XHR request and click it
|
||||
const xhrRequestItem = document.querySelectorAll(".request-list-item")[0];
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, xhrRequestItem);
|
||||
|
||||
const {
|
||||
getSelectedRequest
|
||||
} = windowRequire("devtools/client/netmonitor/src/selectors/index");
|
||||
const firstRequest = getSelectedRequest(store.getState());
|
||||
|
||||
// Open context menu and execute "Edit & Resend".
|
||||
EventUtils.sendMouseEvent({ type: "contextmenu" }, xhrRequestItem);
|
||||
parentDocument.querySelector("#request-list-context-resend").click();
|
||||
|
||||
// Click Resend
|
||||
await waitUntil(() => document.querySelector("#custom-request-send-button"));
|
||||
document.querySelector("#custom-request-send-button").click();
|
||||
|
||||
// Filtering by "other" so the resent request is visible after completion
|
||||
document.querySelector(".requests-list-filter-other-button").click();
|
||||
|
||||
// Select the cloned request
|
||||
document.querySelectorAll(".request-list-item")[0].click();
|
||||
const resendRequest = getSelectedRequest(store.getState());
|
||||
|
||||
ok(resendRequest.id !== firstRequest.id,
|
||||
"The second XHR request was made and is unique");
|
||||
|
||||
ok(resendRequest.id.replace(/-clone$/, "") == firstRequest.id,
|
||||
"The second XHR request is a clone of the first");
|
||||
|
||||
return teardown(monitor);
|
||||
});
|
|
@ -80,8 +80,11 @@
|
|||
#include "mozilla/dom/ChromeMessageSender.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/FrameLoaderBinding.h"
|
||||
#include "mozilla/gfx/CrossProcessPaint.h"
|
||||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "mozilla/layout/RenderFrameParent.h"
|
||||
#include "mozilla/ServoCSSParser.h"
|
||||
#include "mozilla/ServoStyleSet.h"
|
||||
#include "nsGenericHTMLFrameElement.h"
|
||||
#include "GeckoProfiler.h"
|
||||
|
||||
|
@ -129,8 +132,8 @@ typedef FrameMetrics::ViewID ViewID;
|
|||
// itself. Note that "#foo" on the end of URL doesn't affect
|
||||
// whether it's considered identical, but "?foo" or ";foo" are
|
||||
// considered and compared.
|
||||
// Bug 228829: Limit this to 1, like IE does.
|
||||
#define MAX_SAME_URL_CONTENT_FRAMES 1
|
||||
// Limit this to 2, like chromium does.
|
||||
#define MAX_SAME_URL_CONTENT_FRAMES 2
|
||||
|
||||
// Bug 8065: Limit content frame depth to some reasonable level. This
|
||||
// does not count chrome frames when determining depth, nor does it
|
||||
|
@ -3103,6 +3106,64 @@ nsFrameLoader::Print(uint64_t aOuterWindowID,
|
|||
#endif
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::Promise>
|
||||
nsFrameLoader::DrawSnapshot(double aX,
|
||||
double aY,
|
||||
double aW,
|
||||
double aH,
|
||||
double aScale,
|
||||
const nsAString& aBackgroundColor,
|
||||
mozilla::ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<nsIGlobalObject> global = GetOwnerContent()->GetOwnerGlobal();
|
||||
RefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<nsIDocument> document = GetOwnerContent()->GetOwnerDocument();
|
||||
if (NS_WARN_IF(!document)) {
|
||||
aRv = NS_ERROR_FAILURE;
|
||||
return nullptr;
|
||||
}
|
||||
nsIPresShell* presShell = document->GetShell();
|
||||
if (NS_WARN_IF(!presShell)) {
|
||||
aRv = NS_ERROR_FAILURE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nscolor color;
|
||||
css::Loader* loader = document->CSSLoader();
|
||||
ServoStyleSet* set = presShell->StyleSet();
|
||||
if (NS_WARN_IF(!ServoCSSParser::ComputeColor(set,
|
||||
NS_RGB(0, 0, 0),
|
||||
aBackgroundColor,
|
||||
&color,
|
||||
nullptr,
|
||||
loader))) {
|
||||
aRv = NS_ERROR_FAILURE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gfx::IntRect rect = gfx::IntRect::RoundOut(gfx::Rect(aX, aY, aW, aH));
|
||||
|
||||
if (IsRemoteFrame()) {
|
||||
gfx::CrossProcessPaint::StartRemote(mRemoteBrowser->GetTabId(),
|
||||
rect,
|
||||
aScale,
|
||||
color,
|
||||
promise);
|
||||
} else {
|
||||
gfx::CrossProcessPaint::StartLocal(mDocShell,
|
||||
rect,
|
||||
aScale,
|
||||
color,
|
||||
promise);
|
||||
}
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsITabParent>
|
||||
nsFrameLoader::GetTabParent()
|
||||
{
|
||||
|
|
|
@ -171,6 +171,15 @@ public:
|
|||
nsIWebProgressListener* aProgressListener,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<mozilla::dom::Promise>
|
||||
DrawSnapshot(double aX,
|
||||
double aY,
|
||||
double aW,
|
||||
double aH,
|
||||
double aScale,
|
||||
const nsAString& aBackgroundColor,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
void StartPersistence(uint64_t aOuterWindowID,
|
||||
nsIWebBrowserPersistDocumentReceiver* aRecv,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
|
|
@ -808,6 +808,17 @@ ImageBitmap::ToCloneData() const
|
|||
return result;
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<ImageBitmap>
|
||||
ImageBitmap::CreateFromSourceSurface(nsIGlobalObject* aGlobal,
|
||||
gfx::SourceSurface* aSource,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<layers::Image> data = CreateImageFromSurface(aSource);
|
||||
RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
|
||||
ret->mAllocatedImageData = true;
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<ImageBitmap>
|
||||
ImageBitmap::CreateFromCloneData(nsIGlobalObject* aGlobal,
|
||||
ImageBitmapCloneData* aData)
|
||||
|
|
|
@ -118,6 +118,11 @@ public:
|
|||
UniquePtr<ImageBitmapCloneData>
|
||||
ToCloneData() const;
|
||||
|
||||
static already_AddRefed<ImageBitmap>
|
||||
CreateFromSourceSurface(nsIGlobalObject* aGlobal,
|
||||
gfx::SourceSurface* aSource,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<ImageBitmap>
|
||||
CreateFromCloneData(nsIGlobalObject* aGlobal, ImageBitmapCloneData* aData);
|
||||
|
||||
|
|
|
@ -607,3 +607,4 @@ support-files =
|
|||
[test_getElementsByName_after_mutation.html]
|
||||
[test_bug1279218.html]
|
||||
[test_set_input_files.html]
|
||||
[test_nestediframe.html]
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for same URLs nested iframes</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function reportState(msg) {
|
||||
if (location.href.includes("#")) {
|
||||
parent.postMessage(msg, "*");
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg == "OK 1") {
|
||||
ok(true, "First frame loaded");
|
||||
} else if (msg == "KO 2") {
|
||||
ok(true, "Second frame load failed");
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
ok(false, "Unknown message: " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener("message", event => {
|
||||
reportState(event.data);
|
||||
});
|
||||
|
||||
var recursion;
|
||||
if (!location.href.includes("#")) {
|
||||
recursion = 1;
|
||||
} else {
|
||||
recursion = parseInt(localStorage.recursion) + 1;
|
||||
}
|
||||
localStorage.recursion = "" + recursion;
|
||||
|
||||
var ifr = document.createElement('iframe');
|
||||
ifr.src = location.href.split("#")[0] + "#" + recursion;
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
ifr.onload = function() {
|
||||
reportState("OK " + recursion);
|
||||
}
|
||||
|
||||
ifr.onerror = function() {
|
||||
reportState("KO " + recursion);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -181,6 +181,7 @@ ContentProcessManager::RegisterRemoteFrame(const TabId& aTabId,
|
|||
}
|
||||
|
||||
iter->second.mRemoteFrames[aTabId] = info;
|
||||
mTabProcessMap[aTabId] = aChildCpId;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -200,6 +201,11 @@ ContentProcessManager::UnregisterRemoteFrame(const ContentParentId& aChildCpId,
|
|||
if (remoteFrameIter != iter->second.mRemoteFrames.end()) {
|
||||
iter->second.mRemoteFrames.erase(aChildTabId);
|
||||
}
|
||||
|
||||
auto tabProcessIter = mTabProcessMap.find(aChildTabId);
|
||||
if (tabProcessIter != mTabProcessMap.end()) {
|
||||
mTabProcessMap.erase(tabProcessIter);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -273,6 +279,17 @@ ContentProcessManager::GetRemoteFrameOpenerTabId(const ContentParentId& aChildCp
|
|||
return true;
|
||||
}
|
||||
|
||||
ContentParentId
|
||||
ContentProcessManager::GetTabProcessId(const TabId& aTabId)
|
||||
{
|
||||
auto tabProcessIter = mTabProcessMap.find(aTabId);
|
||||
MOZ_ASSERT(tabProcessIter != mTabProcessMap.end());
|
||||
if (tabProcessIter == mTabProcessMap.end()) {
|
||||
return ContentParentId(0);
|
||||
}
|
||||
return tabProcessIter->second;
|
||||
}
|
||||
|
||||
already_AddRefed<TabParent>
|
||||
ContentProcessManager::GetTabParentByProcessAndTabId(const ContentParentId& aChildCpId,
|
||||
const TabId& aChildTabId)
|
||||
|
|
|
@ -115,6 +115,12 @@ public:
|
|||
/*out*/ContentParentId* aOpenerCpId,
|
||||
/*out*/ TabId* aOpenerTabId);
|
||||
|
||||
/**
|
||||
* Get the ContentParentId of the parent of the given tab id.
|
||||
*/
|
||||
ContentParentId
|
||||
GetTabProcessId(const TabId& aTabId);
|
||||
|
||||
/**
|
||||
* Get all TabParents' Ids managed by the givent content process.
|
||||
* Return empty array when TabParent couldn't be found via aChildCpId
|
||||
|
@ -157,6 +163,7 @@ public:
|
|||
private:
|
||||
static StaticAutoPtr<ContentProcessManager> sSingleton;
|
||||
std::map<ContentParentId, ContentProcessInfo> mContentParentMap;
|
||||
std::map<TabId, ContentParentId> mTabProcessMap;
|
||||
|
||||
ContentProcessManager() {MOZ_COUNT_CTOR(ContentProcessManager);};
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@ include "mozilla/GfxMessageUtils.h";
|
|||
include "mozilla/layers/LayersMessageUtils.h";
|
||||
|
||||
using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
|
||||
using moveonly mozilla::gfx::PaintFragment from "mozilla/gfx/CrossProcessPaint.h";
|
||||
using mozilla::gfx::Matrix from "mozilla/gfx/Matrix.h";
|
||||
using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
|
||||
using mozilla::LayoutDeviceIntPoint from "Units.h";
|
||||
|
@ -766,6 +767,9 @@ child:
|
|||
*/
|
||||
async RenderLayers(bool aEnabled, bool aForceRepaint, LayersObserverEpoch aEpoch);
|
||||
|
||||
async RequestRootPaint(IntRect aRect, float aScale, nscolor aBackgroundColor) returns (PaintFragment retval);
|
||||
async RequestSubPaint(float aScale, nscolor aBackgroundColor) returns (PaintFragment retval);
|
||||
child:
|
||||
/**
|
||||
* Notify the child that it shouldn't paint the offscreen displayport.
|
||||
* This is useful to speed up interactive operations over async
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "mozilla/dom/MessageManagerBinding.h"
|
||||
#include "mozilla/dom/MouseEventBinding.h"
|
||||
#include "mozilla/dom/PaymentRequestChild.h"
|
||||
#include "mozilla/gfx/CrossProcessPaint.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/layers/APZChild.h"
|
||||
|
@ -2667,6 +2668,31 @@ TabChild::RecvRenderLayers(const bool& aEnabled, const bool& aForceRepaint, cons
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
TabChild::RecvRequestRootPaint(const IntRect& aRect, const float& aScale, const nscolor& aBackgroundColor, RequestRootPaintResolver&& aResolve)
|
||||
{
|
||||
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
|
||||
if (!docShell) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
aResolve(gfx::PaintFragment::Record(docShell, aRect, aScale, aBackgroundColor));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
TabChild::RecvRequestSubPaint(const float& aScale, const nscolor& aBackgroundColor, RequestSubPaintResolver&& aResolve)
|
||||
{
|
||||
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
|
||||
if (!docShell) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
gfx::IntRect rect = gfx::RoundedIn(gfx::Rect(0.0f, 0.0f, mUnscaledInnerSize.width, mUnscaledInnerSize.height));
|
||||
aResolve(gfx::PaintFragment::Record(docShell, rect, aScale, aBackgroundColor));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
TabChild::RecvNavigateByKey(const bool& aForward, const bool& aForDocumentNavigation)
|
||||
{
|
||||
|
|
|
@ -724,6 +724,10 @@ protected:
|
|||
|
||||
virtual mozilla::ipc::IPCResult RecvRenderLayers(const bool& aEnabled, const bool& aForce, const layers::LayersObserverEpoch& aEpoch) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvRequestRootPaint(const IntRect& aRect, const float& aScale, const nscolor& aBackgroundColor, RequestRootPaintResolver&& aResolve) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvRequestSubPaint(const float& aScale, const nscolor& aBackgroundColor, RequestSubPaintResolver&& aResolve) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvNavigateByKey(const bool& aForward,
|
||||
const bool& aForDocumentNavigation) override;
|
||||
|
||||
|
|
|
@ -3098,6 +3098,38 @@ TabParent::LayerTreeUpdate(const LayersObserverEpoch& aEpoch, bool aActive)
|
|||
mFrameElement->DispatchEvent(*event);
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::RequestRootPaint(gfx::CrossProcessPaint* aPaint, IntRect aRect, float aScale, nscolor aBackgroundColor)
|
||||
{
|
||||
auto promise = SendRequestRootPaint(aRect, aScale, aBackgroundColor);
|
||||
|
||||
RefPtr<gfx::CrossProcessPaint> paint(aPaint);
|
||||
TabId tabId(GetTabId());
|
||||
promise->Then(GetMainThreadSerialEventTarget(), __func__,
|
||||
[paint, tabId] (PaintFragment&& aFragment) {
|
||||
paint->ReceiveFragment(tabId, std::move(aFragment));
|
||||
},
|
||||
[paint, tabId] (ResponseRejectReason aReason) {
|
||||
paint->LostFragment(tabId);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::RequestSubPaint(gfx::CrossProcessPaint* aPaint, float aScale, nscolor aBackgroundColor)
|
||||
{
|
||||
auto promise = SendRequestSubPaint(aScale, aBackgroundColor);
|
||||
|
||||
RefPtr<gfx::CrossProcessPaint> paint(aPaint);
|
||||
TabId tabId(GetTabId());
|
||||
promise->Then(GetMainThreadSerialEventTarget(), __func__,
|
||||
[paint, tabId] (PaintFragment&& aFragment) {
|
||||
paint->ReceiveFragment(tabId, std::move(aFragment));
|
||||
},
|
||||
[paint, tabId] (ResponseRejectReason aReason) {
|
||||
paint->LostFragment(tabId);
|
||||
});
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
TabParent::RecvPaintWhileInterruptingJSNoOp(const LayersObserverEpoch& aEpoch)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "mozilla/dom/TabContext.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/gfx/CrossProcessPaint.h"
|
||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
@ -562,6 +563,9 @@ public:
|
|||
|
||||
void LayerTreeUpdate(const LayersObserverEpoch& aEpoch, bool aActive);
|
||||
|
||||
void RequestRootPaint(gfx::CrossProcessPaint* aPaint, IntRect aRect, float aScale, nscolor aBackgroundColor);
|
||||
void RequestSubPaint(gfx::CrossProcessPaint* aPaint, float aScale, nscolor aBackgroundColor);
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
|
||||
const uint32_t& aAction,
|
||||
|
|
|
@ -108,6 +108,30 @@ interface FrameLoader {
|
|||
nsIPrintSettings aPrintSettings,
|
||||
optional nsIWebProgressListener? aProgressListener = null);
|
||||
|
||||
/**
|
||||
* Renders a region of the frame into an image bitmap.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param w
|
||||
* @param h Specify the area of the window to render, in CSS
|
||||
* pixels. This is relative to the current scroll position.
|
||||
* @param scale The scale to render the window at. Use devicePixelRatio
|
||||
* to have comparable rendering to the OS.
|
||||
* @param backgroundColor The background color to use.
|
||||
*
|
||||
* This API can only be used in the parent process, as content processes
|
||||
* cannot access the rendering of out of process iframes. This API works
|
||||
* with remote and local frames.
|
||||
*/
|
||||
[Throws]
|
||||
Promise<ImageBitmap> drawSnapshot(double x,
|
||||
double y,
|
||||
double w,
|
||||
double h,
|
||||
double scale,
|
||||
DOMString backgroundColor);
|
||||
|
||||
/**
|
||||
* If false, then the subdocument is not clipped to its CSS viewport, and the
|
||||
* subdocument's viewport scrollbar(s) are not rendered.
|
||||
|
|
|
@ -1037,6 +1037,12 @@ public:
|
|||
const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
|
||||
const DrawOptions &aOptions = DrawOptions()) = 0;
|
||||
|
||||
virtual void DrawDependentSurface(uint64_t aId,
|
||||
const Rect &aDest,
|
||||
const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
|
||||
const DrawOptions &aOptions = DrawOptions())
|
||||
{ MOZ_CRASH("GFX: DrawDependentSurface"); }
|
||||
|
||||
/**
|
||||
* Draw the output of a FilterNode to the DrawTarget.
|
||||
*
|
||||
|
|
|
@ -66,6 +66,18 @@ DrawEventRecorderMemory::RecordEvent(const RecordedEvent &aEvent)
|
|||
aEvent.RecordToStream(mOutputStream);
|
||||
}
|
||||
|
||||
void
|
||||
DrawEventRecorderMemory::AddDependentSurface(uint64_t aDependencyId)
|
||||
{
|
||||
mDependentSurfaces.PutEntry(aDependencyId);
|
||||
}
|
||||
|
||||
nsTHashtable<nsUint64HashKey>&&
|
||||
DrawEventRecorderMemory::TakeDependentSurfaces()
|
||||
{
|
||||
return std::move(mDependentSurfaces);
|
||||
}
|
||||
|
||||
DrawEventRecorderFile::DrawEventRecorderFile(const char_type* aFilename)
|
||||
: mOutputStream(aFilename, ofstream::binary)
|
||||
{
|
||||
|
@ -114,7 +126,7 @@ DrawEventRecorderMemory::DrawEventRecorderMemory()
|
|||
DrawEventRecorderMemory::DrawEventRecorderMemory(const SerializeResourcesFn &aFn) :
|
||||
mSerializeCallback(aFn)
|
||||
{
|
||||
mExternalFonts = true;
|
||||
mExternalFonts = !!mSerializeCallback;
|
||||
WriteHeader(mOutputStream);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
|
@ -110,6 +113,11 @@ public:
|
|||
virtual void StoreSourceSurfaceRecording(SourceSurface *aSurface,
|
||||
const char *aReason);
|
||||
|
||||
virtual void AddDependentSurface(uint64_t aDependencyId)
|
||||
{
|
||||
MOZ_CRASH("GFX: AddDependentSurface");
|
||||
}
|
||||
|
||||
protected:
|
||||
void StoreExternalSurfaceRecording(SourceSurface* aSurface,
|
||||
uint64_t aKey);
|
||||
|
@ -177,6 +185,10 @@ public:
|
|||
|
||||
void RecordEvent(const RecordedEvent &aEvent) override;
|
||||
|
||||
void AddDependentSurface(uint64_t aDependencyId) override;
|
||||
|
||||
nsTHashtable<nsUint64HashKey>&& TakeDependentSurfaces();
|
||||
|
||||
/**
|
||||
* @return the current size of the recording (in chars).
|
||||
*/
|
||||
|
@ -205,6 +217,7 @@ protected:
|
|||
|
||||
private:
|
||||
SerializeResourcesFn mSerializeCallback;
|
||||
nsTHashtable<nsUint64HashKey> mDependentSurfaces;
|
||||
|
||||
void Flush() override;
|
||||
};
|
||||
|
|
|
@ -417,6 +417,16 @@ DrawTargetRecording::DrawSurface(SourceSurface *aSurface,
|
|||
mRecorder->RecordEvent(RecordedDrawSurface(this, aSurface, aDest, aSource, aSurfOptions, aOptions));
|
||||
}
|
||||
|
||||
void
|
||||
DrawTargetRecording::DrawDependentSurface(uint64_t aId,
|
||||
const Rect &aDest,
|
||||
const DrawSurfaceOptions &aSurfOptions,
|
||||
const DrawOptions &aOptions)
|
||||
{
|
||||
mRecorder->AddDependentSurface(aId);
|
||||
mRecorder->RecordEvent(RecordedDrawDependentSurface(this, aId, aDest, aSurfOptions, aOptions));
|
||||
}
|
||||
|
||||
void
|
||||
DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface *aSurface,
|
||||
const Point &aDest,
|
||||
|
|
|
@ -57,6 +57,11 @@ public:
|
|||
const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
|
||||
const DrawOptions &aOptions = DrawOptions()) override;
|
||||
|
||||
virtual void DrawDependentSurface(uint64_t aId,
|
||||
const Rect &aDest,
|
||||
const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
|
||||
const DrawOptions &aOptions = DrawOptions()) override;
|
||||
|
||||
virtual void DrawFilter(FilterNode *aNode,
|
||||
const Rect &aSourceRect,
|
||||
const Point &aDestPoint,
|
||||
|
|
|
@ -34,6 +34,11 @@ public:
|
|||
|
||||
bool TranslateRecording(char *, size_t len);
|
||||
|
||||
void SetExternalSurfaces(nsRefPtrHashtable<nsUint64HashKey, SourceSurface>* aExternalSurfaces)
|
||||
{
|
||||
mExternalSurfaces = aExternalSurfaces;
|
||||
}
|
||||
|
||||
DrawTarget* LookupDrawTarget(ReferencePtr aRefPtr) final
|
||||
{
|
||||
DrawTarget* result = mDrawTargets.GetWeak(aRefPtr);
|
||||
|
@ -90,6 +95,11 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
already_AddRefed<SourceSurface> LookupExternalSurface(uint64_t aKey) override
|
||||
{
|
||||
return mExternalSurfaces->Get(aKey);
|
||||
}
|
||||
|
||||
void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget *aDT) final
|
||||
{
|
||||
mDrawTargets.Put(aRefPtr, aDT);
|
||||
|
@ -187,6 +197,7 @@ private:
|
|||
nsRefPtrHashtable<nsPtrHashKey<void>, ScaledFont> mScaledFonts;
|
||||
nsRefPtrHashtable<nsPtrHashKey<void>, UnscaledFont> mUnscaledFonts;
|
||||
nsRefPtrHashtable<nsUint64HashKey, NativeFontResource> mNativeFontResources;
|
||||
nsRefPtrHashtable<nsUint64HashKey, SourceSurface>* mExternalSurfaces;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
|
|
@ -65,6 +65,8 @@ RecordedEvent::GetEventName(EventType aType)
|
|||
return "Stroke";
|
||||
case DRAWSURFACE:
|
||||
return "DrawSurface";
|
||||
case DRAWDEPENDENTSURFACE:
|
||||
return "DrawDependentSurface";
|
||||
case DRAWSURFACEWITHSHADOW:
|
||||
return "DrawSurfaceWithShadow";
|
||||
case DRAWFILTER:
|
||||
|
|
|
@ -234,6 +234,7 @@ public:
|
|||
MASK,
|
||||
STROKE,
|
||||
DRAWSURFACE,
|
||||
DRAWDEPENDENTSURFACE,
|
||||
DRAWSURFACEWITHSHADOW,
|
||||
PATHCREATION,
|
||||
PATHDESTRUCTION,
|
||||
|
|
|
@ -644,6 +644,35 @@ private:
|
|||
DrawOptions mOptions;
|
||||
};
|
||||
|
||||
class RecordedDrawDependentSurface : public RecordedDrawingEvent<RecordedDrawDependentSurface> {
|
||||
public:
|
||||
RecordedDrawDependentSurface(DrawTarget *aDT, uint64_t aId, const Rect &aDest,
|
||||
const DrawSurfaceOptions &aDSOptions,
|
||||
const DrawOptions &aOptions)
|
||||
: RecordedDrawingEvent(DRAWDEPENDENTSURFACE, aDT), mId(aId), mDest(aDest)
|
||||
, mDSOptions(aDSOptions), mOptions(aOptions)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool PlayEvent(Translator *aTranslator) const override;
|
||||
|
||||
template<class S> void Record(S &aStream) const;
|
||||
virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const override;
|
||||
|
||||
virtual std::string GetName() const override { return "DrawDependentSurface"; }
|
||||
|
||||
private:
|
||||
friend class RecordedEvent;
|
||||
|
||||
template<class S>
|
||||
MOZ_IMPLICIT RecordedDrawDependentSurface(S &aStream);
|
||||
|
||||
uint64_t mId;
|
||||
Rect mDest;
|
||||
DrawSurfaceOptions mDSOptions;
|
||||
DrawOptions mOptions;
|
||||
};
|
||||
|
||||
class RecordedDrawSurfaceWithShadow : public RecordedDrawingEvent<RecordedDrawSurfaceWithShadow> {
|
||||
public:
|
||||
RecordedDrawSurfaceWithShadow(DrawTarget *aDT, ReferencePtr aRefSource, const Point &aDest,
|
||||
|
@ -2431,6 +2460,43 @@ RecordedDrawSurface::OutputSimpleEventInfo(std::stringstream &aStringStream) con
|
|||
aStringStream << "[" << mDT << "] DrawSurface (" << mRefSource << ")";
|
||||
}
|
||||
|
||||
inline bool
|
||||
RecordedDrawDependentSurface::PlayEvent(Translator *aTranslator) const
|
||||
{
|
||||
RefPtr<SourceSurface> surface(aTranslator->LookupExternalSurface(mId));
|
||||
aTranslator->LookupDrawTarget(mDT)->
|
||||
DrawSurface(surface, mDest, Rect(Point(), Size(surface->GetSize())),
|
||||
mDSOptions, mOptions);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class S>
|
||||
void
|
||||
RecordedDrawDependentSurface::Record(S &aStream) const
|
||||
{
|
||||
RecordedDrawingEvent::Record(aStream);
|
||||
WriteElement(aStream, mId);
|
||||
WriteElement(aStream, mDest);
|
||||
WriteElement(aStream, mDSOptions);
|
||||
WriteElement(aStream, mOptions);
|
||||
}
|
||||
|
||||
template<class S>
|
||||
RecordedDrawDependentSurface::RecordedDrawDependentSurface(S &aStream)
|
||||
: RecordedDrawingEvent(DRAWDEPENDENTSURFACE, aStream)
|
||||
{
|
||||
ReadElement(aStream, mId);
|
||||
ReadElement(aStream, mDest);
|
||||
ReadElement(aStream, mDSOptions);
|
||||
ReadElement(aStream, mOptions);
|
||||
}
|
||||
|
||||
inline void
|
||||
RecordedDrawDependentSurface::OutputSimpleEventInfo(std::stringstream &aStringStream) const
|
||||
{
|
||||
aStringStream << "[" << mDT << "] DrawDependentSurface (" << mId << ")";
|
||||
}
|
||||
|
||||
inline bool
|
||||
RecordedDrawFilter::PlayEvent(Translator *aTranslator) const
|
||||
{
|
||||
|
@ -3443,6 +3509,7 @@ RecordedFilterNodeSetInput::OutputSimpleEventInfo(std::stringstream &aStringStre
|
|||
f(MASK, RecordedMask); \
|
||||
f(STROKE, RecordedStroke); \
|
||||
f(DRAWSURFACE, RecordedDrawSurface); \
|
||||
f(DRAWDEPENDENTSURFACE, RecordedDrawDependentSurface); \
|
||||
f(DRAWSURFACEWITHSHADOW, RecordedDrawSurfaceWithShadow); \
|
||||
f(DRAWFILTER, RecordedDrawFilter); \
|
||||
f(PATHCREATION, RecordedPathCreation); \
|
||||
|
|
|
@ -0,0 +1,427 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "CrossProcessPaint.h"
|
||||
|
||||
#include "mozilla/dom/ContentProcessManager.h"
|
||||
#include "mozilla/dom/ImageBitmap.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/gfx/DrawEventRecorder.h"
|
||||
#include "mozilla/gfx/InlineTranslator.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindowInner.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsPresContext.h"
|
||||
|
||||
#define ENABLE_PAINT_LOG 0
|
||||
// #define ENABLE_PAINT_LOG 1
|
||||
|
||||
#if ENABLE_PAINT_LOG
|
||||
# define PF_LOG(...) printf_stderr("PaintFragment: " __VA_ARGS__)
|
||||
# define CPP_LOG(...) printf_stderr("CrossProcessPaint: " __VA_ARGS__)
|
||||
#else
|
||||
# define PF_LOG(...)
|
||||
# define CPP_LOG(...)
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
/// The minimum scale we allow tabs to be rasterized at.
|
||||
static const float kMinPaintScale = 0.05;
|
||||
|
||||
/* static */ PaintFragment
|
||||
PaintFragment::Record(nsIDocShell* aDocShell,
|
||||
const IntRect& aRect,
|
||||
float aScale,
|
||||
nscolor aBackgroundColor)
|
||||
{
|
||||
IntSize surfaceSize = aRect.Size();
|
||||
surfaceSize.width *= aScale;
|
||||
surfaceSize.height *= aScale;
|
||||
|
||||
CPP_LOG("Recording "
|
||||
"[docshell=%p, "
|
||||
"rect=(%d, %d) x (%d, %d), "
|
||||
"scale=%f, "
|
||||
"color=(%u, %u, %u, %u)]\n",
|
||||
aDocShell,
|
||||
aRect.x, aRect.y, aRect.width, aRect.height,
|
||||
aScale,
|
||||
NS_GET_R(aBackgroundColor),
|
||||
NS_GET_G(aBackgroundColor),
|
||||
NS_GET_B(aBackgroundColor),
|
||||
NS_GET_A(aBackgroundColor));
|
||||
|
||||
// Check for invalid sizes
|
||||
if (surfaceSize.width <= 0 || surfaceSize.height <= 0 ||
|
||||
!Factory::CheckSurfaceSize(surfaceSize)) {
|
||||
PF_LOG("Invalid surface size of (%d x %d).\n",
|
||||
surfaceSize.width,
|
||||
surfaceSize.height);
|
||||
return PaintFragment{};
|
||||
}
|
||||
|
||||
// Flush any pending notifications
|
||||
nsContentUtils::FlushLayoutForTree(aDocShell->GetWindow());
|
||||
|
||||
// Grab the presentation shell to render
|
||||
RefPtr<nsPresContext> presContext;
|
||||
if (aDocShell) {
|
||||
aDocShell->GetPresContext(getter_AddRefs(presContext));
|
||||
}
|
||||
if (!presContext) {
|
||||
PF_LOG("Couldn't find PresContext.\n");
|
||||
return PaintFragment{};
|
||||
}
|
||||
|
||||
// Initialize the recorder
|
||||
SurfaceFormat format = SurfaceFormat::B8G8R8A8;
|
||||
RefPtr<DrawTarget> referenceDt =
|
||||
Factory::CreateDrawTarget(gfxPlatform::GetPlatform()->GetSoftwareBackend(),
|
||||
IntSize(1, 1),
|
||||
format);
|
||||
|
||||
// TODO: This may OOM crash if the content is complex enough
|
||||
RefPtr<DrawEventRecorderMemory> recorder =
|
||||
MakeAndAddRef<DrawEventRecorderMemory>(nullptr);
|
||||
RefPtr<DrawTarget> dt =
|
||||
Factory::CreateRecordingDrawTarget(recorder, referenceDt, surfaceSize);
|
||||
|
||||
// Perform the actual rendering
|
||||
{
|
||||
nsRect r(nsPresContext::CSSPixelsToAppUnits(aRect.x),
|
||||
nsPresContext::CSSPixelsToAppUnits(aRect.y),
|
||||
nsPresContext::CSSPixelsToAppUnits(aRect.width),
|
||||
nsPresContext::CSSPixelsToAppUnits(aRect.height));
|
||||
|
||||
RefPtr<gfxContext> thebes = gfxContext::CreateOrNull(dt);
|
||||
thebes->SetMatrix(Matrix::Scaling(aScale, aScale));
|
||||
nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
|
||||
Unused << shell->RenderDocument(r, 0, aBackgroundColor, thebes);
|
||||
}
|
||||
|
||||
ByteBuf recording = ByteBuf((uint8_t*)recorder->mOutputStream.mData,
|
||||
recorder->mOutputStream.mLength,
|
||||
recorder->mOutputStream.mCapacity);
|
||||
recorder->mOutputStream.mData = nullptr;
|
||||
recorder->mOutputStream.mLength = 0;
|
||||
recorder->mOutputStream.mCapacity = 0;
|
||||
|
||||
return PaintFragment{
|
||||
surfaceSize,
|
||||
std::move(recording),
|
||||
std::move(recorder->TakeDependentSurfaces()),
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
PaintFragment::IsEmpty() const
|
||||
{
|
||||
return !mRecording.mData || mRecording.mLen == 0 || mSize == IntSize(0, 0);
|
||||
}
|
||||
|
||||
PaintFragment::PaintFragment(IntSize aSize,
|
||||
ByteBuf&& aRecording,
|
||||
nsTHashtable<nsUint64HashKey>&& aDependencies)
|
||||
: mSize(aSize)
|
||||
, mRecording(std::move(aRecording))
|
||||
, mDependencies(std::move(aDependencies))
|
||||
{
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
CrossProcessPaint::StartLocal(nsIDocShell* aRoot,
|
||||
const IntRect& aRect,
|
||||
float aScale,
|
||||
nscolor aBackgroundColor,
|
||||
dom::Promise* aPromise)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
|
||||
aScale = std::max(aScale, kMinPaintScale);
|
||||
|
||||
CPP_LOG("Starting local paint. "
|
||||
"[docshell=%p, "
|
||||
"rect=(%d, %d) x (%d, %d), "
|
||||
"scale=%f, "
|
||||
"color=(%u, %u, %u, %u)]\n",
|
||||
aRoot,
|
||||
aRect.x, aRect.y, aRect.width, aRect.height,
|
||||
aScale,
|
||||
NS_GET_R(aBackgroundColor),
|
||||
NS_GET_G(aBackgroundColor),
|
||||
NS_GET_B(aBackgroundColor),
|
||||
NS_GET_A(aBackgroundColor));
|
||||
|
||||
RefPtr<CrossProcessPaint> resolver = new CrossProcessPaint(aPromise,
|
||||
aScale,
|
||||
aBackgroundColor,
|
||||
dom::TabId(0));
|
||||
resolver->ReceiveFragment(dom::TabId(0),
|
||||
PaintFragment::Record(aRoot,
|
||||
aRect,
|
||||
aScale,
|
||||
aBackgroundColor));
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
CrossProcessPaint::StartRemote(dom::TabId aRoot,
|
||||
const IntRect& aRect,
|
||||
float aScale,
|
||||
nscolor aBackgroundColor,
|
||||
dom::Promise* aPromise)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
|
||||
aScale = std::max(aScale, kMinPaintScale);
|
||||
|
||||
CPP_LOG("Starting remote paint. "
|
||||
"[tab=%llu, "
|
||||
"rect=(%d, %d) x (%d, %d), "
|
||||
"scale=%f, "
|
||||
"color=(%u, %u, %u, %u)]\n",
|
||||
(uint64_t)aRoot,
|
||||
aRect.x, aRect.y, aRect.width, aRect.height,
|
||||
aScale,
|
||||
NS_GET_R(aBackgroundColor),
|
||||
NS_GET_G(aBackgroundColor),
|
||||
NS_GET_B(aBackgroundColor),
|
||||
NS_GET_A(aBackgroundColor));
|
||||
|
||||
RefPtr<CrossProcessPaint> resolver = new CrossProcessPaint(aPromise,
|
||||
aScale,
|
||||
aBackgroundColor,
|
||||
aRoot);
|
||||
resolver->QueueRootPaint(aRoot, aRect, aScale, aBackgroundColor);
|
||||
}
|
||||
|
||||
CrossProcessPaint::CrossProcessPaint(dom::Promise* aPromise,
|
||||
float aScale,
|
||||
nscolor aBackgroundColor,
|
||||
dom::TabId aRootId)
|
||||
: mPromise{aPromise}
|
||||
, mRootId{aRootId}
|
||||
, mScale{aScale}
|
||||
, mBackgroundColor{aBackgroundColor}
|
||||
, mPendingFragments{1}
|
||||
{
|
||||
}
|
||||
|
||||
CrossProcessPaint::~CrossProcessPaint()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CrossProcessPaint::ReceiveFragment(dom::TabId aId, PaintFragment&& aFragment)
|
||||
{
|
||||
if (IsCleared()) {
|
||||
CPP_LOG("Ignoring fragment from %llu.\n", (uint64_t)aId);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPendingFragments > 0);
|
||||
MOZ_ASSERT(!mReceivedFragments.GetValue(aId));
|
||||
MOZ_ASSERT(!aFragment.IsEmpty());
|
||||
|
||||
// Double check our invariants to protect against a compromised content
|
||||
// process
|
||||
if (mPendingFragments == 0 ||
|
||||
mReceivedFragments.GetValue(aId) ||
|
||||
aFragment.IsEmpty()) {
|
||||
CPP_LOG("Dropping invalid fragment from %llu.\n", (uint64_t)aId);
|
||||
LostFragment(aId);
|
||||
return;
|
||||
}
|
||||
|
||||
CPP_LOG("Receiving fragment from %llu.\n", (uint64_t)aId);
|
||||
|
||||
// Queue paints for child tabs
|
||||
for (auto iter = aFragment.mDependencies.Iter(); !iter.Done(); iter.Next()) {
|
||||
auto dependency = iter.Get()->GetKey();
|
||||
QueueSubPaint(dom::TabId(dependency));
|
||||
}
|
||||
|
||||
mReceivedFragments.Put(aId, std::move(aFragment));
|
||||
mPendingFragments -= 1;
|
||||
|
||||
// Resolve this paint if we have received all pending fragments
|
||||
MaybeResolve();
|
||||
}
|
||||
|
||||
void
|
||||
CrossProcessPaint::LostFragment(dom::TabId aId)
|
||||
{
|
||||
if (IsCleared()) {
|
||||
CPP_LOG("Ignoring lost fragment from %llu.\n", (uint64_t)aId);
|
||||
return;
|
||||
}
|
||||
|
||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||
Clear();
|
||||
}
|
||||
|
||||
void
|
||||
CrossProcessPaint::QueueRootPaint(dom::TabId aId,
|
||||
const IntRect& aRect,
|
||||
float aScale,
|
||||
nscolor aBackgroundColor)
|
||||
{
|
||||
MOZ_ASSERT(!mReceivedFragments.GetValue(aId));
|
||||
MOZ_ASSERT(mPendingFragments == 1);
|
||||
|
||||
CPP_LOG("Queueing root paint for %llu.\n", (uint64_t)aId);
|
||||
|
||||
dom::ContentProcessManager* cpm = dom::ContentProcessManager::GetSingleton();
|
||||
|
||||
dom::ContentParentId cpId = cpm->GetTabProcessId(aId);
|
||||
RefPtr<dom::TabParent> tab = cpm->GetTabParentByProcessAndTabId(cpId, aId);
|
||||
tab->RequestRootPaint(this, aRect, aScale, aBackgroundColor);
|
||||
|
||||
// This will always be the first paint, so the constructor will already have
|
||||
// incremented one pending fragment
|
||||
}
|
||||
|
||||
void
|
||||
CrossProcessPaint::QueueSubPaint(dom::TabId aId)
|
||||
{
|
||||
MOZ_ASSERT(!mReceivedFragments.GetValue((uint64_t)aId));
|
||||
|
||||
CPP_LOG("Queueing sub paint for %llu.\n", (uint64_t)aId);
|
||||
|
||||
dom::ContentProcessManager* cpm = dom::ContentProcessManager::GetSingleton();
|
||||
|
||||
dom::ContentParentId cpId = cpm->GetTabProcessId(aId);
|
||||
RefPtr<dom::TabParent> tab = cpm->GetTabParentByProcessAndTabId(cpId, aId);
|
||||
tab->RequestSubPaint(this, mScale, mBackgroundColor);
|
||||
|
||||
mPendingFragments += 1;
|
||||
}
|
||||
|
||||
void
|
||||
CrossProcessPaint::Clear()
|
||||
{
|
||||
mPromise = nullptr;
|
||||
mPendingFragments = 0;
|
||||
mReceivedFragments.Clear();
|
||||
}
|
||||
|
||||
bool
|
||||
CrossProcessPaint::IsCleared() const
|
||||
{
|
||||
return !mPromise;
|
||||
}
|
||||
|
||||
void
|
||||
CrossProcessPaint::MaybeResolve()
|
||||
{
|
||||
// Don't do anything if we aren't ready, experienced an error, or already
|
||||
// resolved this paint
|
||||
if (IsCleared() || mPendingFragments > 0) {
|
||||
CPP_LOG("Not ready to resolve yet, have %u fragments left.\n",
|
||||
mPendingFragments);
|
||||
return;
|
||||
}
|
||||
|
||||
CPP_LOG("Starting to resolve fragments.\n");
|
||||
|
||||
// Resolve the paint fragments from the bottom up
|
||||
ResolvedSurfaceMap resolved;
|
||||
if (!ResolveInternal(mRootId, &resolved)) {
|
||||
CPP_LOG("Couldn't resolve.\n");
|
||||
|
||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab the result from the resolved table
|
||||
RefPtr<SourceSurface> root = resolved.Get(mRootId);
|
||||
CPP_LOG("Resolved all fragments.\n");
|
||||
|
||||
ErrorResult rv;
|
||||
RefPtr<dom::ImageBitmap> bitmap =
|
||||
dom::ImageBitmap::CreateFromSourceSurface(mPromise->GetParentObject(),
|
||||
root,
|
||||
rv);
|
||||
|
||||
if (!rv.Failed()) {
|
||||
CPP_LOG("Success, fulfilling promise.\n");
|
||||
mPromise->MaybeResolve(bitmap);
|
||||
} else {
|
||||
CPP_LOG("Couldn't create ImageBitmap for SourceSurface.\n");
|
||||
mPromise->MaybeReject(rv);
|
||||
}
|
||||
Clear();
|
||||
}
|
||||
|
||||
bool
|
||||
CrossProcessPaint::ResolveInternal(dom::TabId aId,
|
||||
ResolvedSurfaceMap* aResolved)
|
||||
{
|
||||
// We should not have resolved this paint already
|
||||
MOZ_ASSERT(!aResolved->GetWeak(aId));
|
||||
|
||||
CPP_LOG("Resolving fragment %llu.\n", (uint64_t)aId);
|
||||
|
||||
Maybe<PaintFragment> fragment = mReceivedFragments.GetAndRemove(aId);
|
||||
|
||||
// Rasterize all the dependencies first so that we can resolve this fragment
|
||||
for (auto iter = fragment->mDependencies.Iter(); !iter.Done(); iter.Next()) {
|
||||
auto dependency = iter.Get()->GetKey();
|
||||
if (!ResolveInternal(dom::TabId(dependency), aResolved)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the destination draw target
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(fragment->mSize,
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
if (!drawTarget || !drawTarget->IsValid()) {
|
||||
CPP_LOG("Couldn't create (%d x %d) surface for fragment %llu.\n",
|
||||
fragment->mSize.width,
|
||||
fragment->mSize.height,
|
||||
(uint64_t)aId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Translate the recording using our child tabs
|
||||
{
|
||||
InlineTranslator translator(drawTarget, nullptr);
|
||||
translator.SetExternalSurfaces(aResolved);
|
||||
if (!translator.TranslateRecording((char*)fragment->mRecording.mData,
|
||||
fragment->mRecording.mLen)) {
|
||||
CPP_LOG("Couldn't translate recording for fragment %llu.\n",
|
||||
(uint64_t)aId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> snapshot = drawTarget->Snapshot();
|
||||
if (!snapshot) {
|
||||
CPP_LOG("Couldn't get snapshot for fragment %llu.\n",
|
||||
(uint64_t)aId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We are done with the resolved images of our dependencies, let's remove
|
||||
// them
|
||||
for (auto iter = fragment->mDependencies.Iter(); !iter.Done(); iter.Next()) {
|
||||
auto dependency = iter.Get()->GetKey();
|
||||
aResolved->Remove(dependency);
|
||||
}
|
||||
|
||||
aResolved->Put(aId, snapshot);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,170 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 _include_mozilla_gfx_ipc_CrossProcessPaint_h_
|
||||
#define _include_mozilla_gfx_ipc_CrossProcessPaint_h_
|
||||
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/ipc/ByteBuf.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
||||
namespace IPC {
|
||||
template<typename T> struct ParamTraits;
|
||||
} // namespace IPC
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
class CrossProcessPaint;
|
||||
|
||||
/**
|
||||
* A fragment of a paint of a cross process document tree.
|
||||
*/
|
||||
class PaintFragment
|
||||
{
|
||||
public:
|
||||
/// Initializes an empty PaintFragment
|
||||
PaintFragment() = default;
|
||||
|
||||
/**
|
||||
* Creates a paint fragment by recording the draw commands and dependent tabs
|
||||
* for an nsIDocShell.
|
||||
*
|
||||
* @param aDocShell The document shell to record.
|
||||
* @param aRect The rectangle relative to the viewport to use.
|
||||
* @param aScale The coordinate scale to use. The size of the resolved
|
||||
* surface will be `aRect.Size() * aScale`, with aScale clamped to
|
||||
* at least kMinPaintScale.
|
||||
* @param aBackgroundColor The background color to use.
|
||||
*
|
||||
* @return A paint fragment. The paint fragment may be `empty` if rendering
|
||||
* was unable to be accomplished for some reason.
|
||||
*/
|
||||
static PaintFragment Record(nsIDocShell* aDocShell,
|
||||
const IntRect& aRect,
|
||||
float aScale,
|
||||
nscolor aBackgroundColor);
|
||||
|
||||
/// Returns whether this paint fragment contains a valid recording.
|
||||
bool IsEmpty() const;
|
||||
|
||||
PaintFragment(PaintFragment&&) = default;
|
||||
PaintFragment& operator=(PaintFragment&&) = default;
|
||||
|
||||
protected:
|
||||
friend struct IPC::ParamTraits<PaintFragment>;
|
||||
friend CrossProcessPaint;
|
||||
|
||||
typedef mozilla::ipc::ByteBuf ByteBuf;
|
||||
|
||||
PaintFragment(IntSize, ByteBuf&&, nsTHashtable<nsUint64HashKey>&&);
|
||||
|
||||
IntSize mSize;
|
||||
ByteBuf mRecording;
|
||||
nsTHashtable<nsUint64HashKey> mDependencies;
|
||||
};
|
||||
|
||||
/**
|
||||
* An object for painting a cross process document tree.
|
||||
*/
|
||||
class CrossProcessPaint
|
||||
{
|
||||
NS_INLINE_DECL_REFCOUNTING(CrossProcessPaint);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Begin an asynchronous paint of a cross process document tree starting at
|
||||
* a local document shell. The local document will be painted, then async
|
||||
* paints will be queued for remote subframes. Once all subframes have been
|
||||
* recorded, the final image will be resolved, and the promise will be
|
||||
* resolved with a dom::ImageBitmap.
|
||||
*
|
||||
* @param aDocShell The document shell to paint.
|
||||
* @param aRect The rectangle relative to the viewport to use.
|
||||
* @param aScale The coordinate scale to use. The size of the resolved
|
||||
* surface will be `aRect.Size() * aScale`, with aScale clamped to
|
||||
* at least kMinPaintScale. See the implementation for the current
|
||||
* minimum value.
|
||||
* @param aBackgroundColor The background color to use.
|
||||
* @param aPromise The promise to resolve with a dom::ImageBitmap.
|
||||
*/
|
||||
static void StartLocal(nsIDocShell* aRoot,
|
||||
const IntRect& aRect,
|
||||
float aScale,
|
||||
nscolor aBackgroundColor,
|
||||
dom::Promise* aPromise);
|
||||
|
||||
/**
|
||||
* Begin an asynchronous paint of a cross process document tree starting at
|
||||
* a remote tab. An async paint for the remote tab will be queued, then async
|
||||
* paints will be recursively queued for remote subframes. Once all subframes
|
||||
* have been recorded, the final image will be resolved, and the promise will
|
||||
* be resolved with a dom::ImageBitmap.
|
||||
*
|
||||
* @param aDocShell The document shell to paint.
|
||||
* @param aRect The rectangle relative to the viewport to use.
|
||||
* @param aScale The coordinate scale to use. The size of the resolved
|
||||
* surface will be `aRect.Size() * aScale`, with aScale clamped to
|
||||
* at least kMinPaintScale. See the implementation for the current
|
||||
* minimum value.
|
||||
* @param aBackgroundColor The background color to use.
|
||||
* @param aPromise The promise to resolve with a dom::ImageBitmap.
|
||||
*/
|
||||
static void StartRemote(dom::TabId aRoot,
|
||||
const IntRect& aRect,
|
||||
float aScale,
|
||||
nscolor aBackgroundColor,
|
||||
dom::Promise* aPromise);
|
||||
|
||||
void ReceiveFragment(dom::TabId aId, PaintFragment&& aFragment);
|
||||
void LostFragment(dom::TabId aId);
|
||||
private:
|
||||
typedef nsRefPtrHashtable<nsUint64HashKey, SourceSurface> ResolvedSurfaceMap;
|
||||
typedef nsDataHashtable<nsUint64HashKey, PaintFragment> ReceivedFragmentMap;
|
||||
|
||||
CrossProcessPaint(dom::Promise* aPromise,
|
||||
float aScale,
|
||||
nscolor aBackgroundColor,
|
||||
dom::TabId aRootId);
|
||||
~CrossProcessPaint();
|
||||
|
||||
void QueueRootPaint(dom::TabId aId,
|
||||
const IntRect& aRect,
|
||||
float aScale,
|
||||
nscolor aBackgroundColor);
|
||||
void QueueSubPaint(dom::TabId aId);
|
||||
|
||||
/// Clear the state of this paint so that it cannot be resolved or receive
|
||||
/// any paint fragments.
|
||||
void Clear();
|
||||
|
||||
/// Returns if this paint has been cleared.
|
||||
bool IsCleared() const;
|
||||
|
||||
/// Resolves the paint fragments if we have none pending and resolves the
|
||||
/// promise.
|
||||
void MaybeResolve();
|
||||
bool ResolveInternal(dom::TabId aId,
|
||||
ResolvedSurfaceMap* aResolved);
|
||||
|
||||
RefPtr<dom::Promise> mPromise;
|
||||
dom::TabId mRootId;
|
||||
float mScale;
|
||||
nscolor mBackgroundColor;
|
||||
uint32_t mPendingFragments;
|
||||
ReceivedFragmentMap mReceivedFragments;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // _include_mozilla_gfx_ipc_CrossProcessPaint_h_
|
|
@ -20,6 +20,7 @@
|
|||
#include "gfxTelemetry.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
#include "mozilla/gfx/CrossProcessPaint.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsRegion.h"
|
||||
|
@ -1279,6 +1280,23 @@ struct ParamTraits<mozilla::Array<T, Length>>
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<mozilla::gfx::PaintFragment>
|
||||
{
|
||||
typedef mozilla::gfx::PaintFragment paramType;
|
||||
static void Write(Message* aMsg, paramType& aParam) {
|
||||
WriteParam(aMsg, aParam.mSize);
|
||||
WriteParam(aMsg, aParam.mRecording);
|
||||
WriteParam(aMsg, aParam.mDependencies);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) {
|
||||
return ReadParam(aMsg, aIter, &aResult->mSize) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mRecording) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mDependencies);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace IPC */
|
||||
|
||||
#endif /* __GFXMESSAGEUTILS_H__ */
|
||||
|
|
|
@ -13,6 +13,7 @@ EXPORTS.mozilla += [
|
|||
]
|
||||
|
||||
EXPORTS.mozilla.gfx += [
|
||||
'CrossProcessPaint.h',
|
||||
'GPUChild.h',
|
||||
'GPUParent.h',
|
||||
'GPUProcessHost.h',
|
||||
|
@ -49,6 +50,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|||
UNIFIED_SOURCES += [
|
||||
'CompositorSession.cpp',
|
||||
'CompositorWidgetVsyncObserver.cpp',
|
||||
'CrossProcessPaint.cpp',
|
||||
'D3DMessageUtils.cpp',
|
||||
'GPUChild.cpp',
|
||||
'GPUProcessHost.cpp',
|
||||
|
|
|
@ -58,6 +58,14 @@ public:
|
|||
aFrom.mCapacity = 0;
|
||||
}
|
||||
|
||||
ByteBuf& operator=(ByteBuf&& aFrom)
|
||||
{
|
||||
std::swap(mData, aFrom.mData);
|
||||
std::swap(mLen, aFrom.mLen);
|
||||
std::swap(mCapacity, aFrom.mCapacity);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ByteBuf()
|
||||
{
|
||||
free(mData);
|
||||
|
|
|
@ -30,11 +30,13 @@
|
|||
#include <type_traits>
|
||||
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsID.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "nsCSSPropertyID.h"
|
||||
|
||||
|
@ -537,6 +539,39 @@ struct ParamTraits<nsAutoString> : ParamTraits<nsString>
|
|||
|
||||
#endif // MOZILLA_INTERNAL_API
|
||||
|
||||
template <>
|
||||
struct ParamTraits<nsTHashtable<nsUint64HashKey>>
|
||||
{
|
||||
typedef nsTHashtable<nsUint64HashKey> paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
uint32_t count = aParam.Count();
|
||||
WriteParam(aMsg, count);
|
||||
for (auto iter = aParam.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
WriteParam(aMsg, iter.Get()->GetKey());
|
||||
}
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
uint32_t count;
|
||||
if (!ReadParam(aMsg, aIter, &count)) {
|
||||
return false;
|
||||
}
|
||||
paramType table(count);
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
uint64_t key;
|
||||
if (!ReadParam(aMsg, aIter, &key)) {
|
||||
return false;
|
||||
}
|
||||
table.PutEntry(key);
|
||||
}
|
||||
*aResult = std::move(table);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Pickle::ReadBytes and ::WriteBytes take the length in ints, so we must
|
||||
// ensure there is no overflow. This returns |false| if it would overflow.
|
||||
// Otherwise, it returns |true| and places the byte length in |aByteLength|.
|
||||
|
|
|
@ -177,7 +177,8 @@ class Include(Node):
|
|||
|
||||
|
||||
class UsingStmt(Node):
|
||||
def __init__(self, loc, cxxTypeSpec, cxxHeader=None, kind=None, refcounted=False):
|
||||
def __init__(self, loc, cxxTypeSpec, cxxHeader=None, kind=None,
|
||||
refcounted=False, moveonly=False):
|
||||
Node.__init__(self, loc)
|
||||
assert not isinstance(cxxTypeSpec, str)
|
||||
assert cxxHeader is None or isinstance(cxxHeader, str)
|
||||
|
@ -186,6 +187,7 @@ class UsingStmt(Node):
|
|||
self.header = cxxHeader
|
||||
self.kind = kind
|
||||
self.refcounted = refcounted
|
||||
self.moveonly = moveonly
|
||||
|
||||
def canBeForwardDeclared(self):
|
||||
return self.isClass() or self.isStruct()
|
||||
|
@ -199,6 +201,9 @@ class UsingStmt(Node):
|
|||
def isRefcounted(self):
|
||||
return self.refcounted
|
||||
|
||||
def isMoveonly(self):
|
||||
return self.moveonly
|
||||
|
||||
# "singletons"
|
||||
|
||||
|
||||
|
|
|
@ -598,6 +598,9 @@ def _cxxConstRefType(ipdltype, side):
|
|||
t.const = inner.const or not inner.ref
|
||||
t.ref = 1
|
||||
return t
|
||||
if ipdltype.isCxx() and ipdltype.isMoveonly():
|
||||
t.ref = 1
|
||||
return t
|
||||
if ipdltype.isCxx() and ipdltype.isRefcounted():
|
||||
# Use T* instead of const RefPtr<T>&
|
||||
t = t.T
|
||||
|
@ -609,10 +612,11 @@ def _cxxConstRefType(ipdltype, side):
|
|||
|
||||
|
||||
def _cxxTypeNeedsMove(ipdltype):
|
||||
return ipdltype.isIPDL() and (ipdltype.isArray() or
|
||||
ipdltype.isShmem() or
|
||||
ipdltype.isByteBuf() or
|
||||
ipdltype.isEndpoint())
|
||||
return ((ipdltype.isIPDL() and (ipdltype.isArray() or
|
||||
ipdltype.isShmem() or
|
||||
ipdltype.isByteBuf() or
|
||||
ipdltype.isEndpoint())) or
|
||||
(ipdltype.isCxx() and ipdltype.isMoveonly()))
|
||||
|
||||
|
||||
def _cxxTypeCanMove(ipdltype):
|
||||
|
|
|
@ -132,6 +132,7 @@ reserved = set((
|
|||
'prio',
|
||||
'protocol',
|
||||
'refcounted',
|
||||
'moveonly',
|
||||
'returns',
|
||||
'struct',
|
||||
'sync',
|
||||
|
@ -288,13 +289,20 @@ def p_MaybeRefcounted(p):
|
|||
p[0] = 2 == len(p)
|
||||
|
||||
|
||||
def p_MaybeMoveOnly(p):
|
||||
"""MaybeMoveOnly : MOVEONLY
|
||||
|"""
|
||||
p[0] = 2 == len(p)
|
||||
|
||||
|
||||
def p_UsingStmt(p):
|
||||
"""UsingStmt : USING MaybeRefcounted UsingKind CxxType FROM STRING"""
|
||||
"""UsingStmt : USING MaybeRefcounted MaybeMoveOnly UsingKind CxxType FROM STRING"""
|
||||
p[0] = UsingStmt(locFromTok(p, 1),
|
||||
refcounted=p[2],
|
||||
kind=p[3],
|
||||
cxxTypeSpec=p[4],
|
||||
cxxHeader=p[6])
|
||||
moveonly=p[3],
|
||||
kind=p[4],
|
||||
cxxTypeSpec=p[5],
|
||||
cxxHeader=p[7])
|
||||
|
||||
# --------------------
|
||||
# Namespaced stuff
|
||||
|
|
|
@ -142,11 +142,12 @@ VOID = VoidType()
|
|||
|
||||
|
||||
class ImportedCxxType(Type):
|
||||
def __init__(self, qname, refcounted):
|
||||
def __init__(self, qname, refcounted, moveonly):
|
||||
assert isinstance(qname, QualifiedId)
|
||||
self.loc = qname.loc
|
||||
self.qname = qname
|
||||
self.refcounted = refcounted
|
||||
self.moveonly = moveonly
|
||||
|
||||
def isCxx(self):
|
||||
return True
|
||||
|
@ -157,6 +158,9 @@ class ImportedCxxType(Type):
|
|||
def isRefcounted(self):
|
||||
return self.refcounted
|
||||
|
||||
def isMoveonly(self):
|
||||
return self.moveonly
|
||||
|
||||
def name(self):
|
||||
return self.qname.baseid
|
||||
|
||||
|
@ -848,12 +852,15 @@ class GatherDecls(TcheckVisitor):
|
|||
elif fullname == 'mozilla::ipc::FileDescriptor':
|
||||
ipdltype = FDType(using.type.spec)
|
||||
else:
|
||||
ipdltype = ImportedCxxType(using.type.spec, using.isRefcounted())
|
||||
ipdltype = ImportedCxxType(using.type.spec, using.isRefcounted(), using.isMoveonly())
|
||||
existingType = self.symtab.lookup(ipdltype.fullname())
|
||||
if existingType and existingType.fullname == ipdltype.fullname():
|
||||
if ipdltype.isRefcounted() != existingType.type.isRefcounted():
|
||||
self.error(using.loc, "inconsistent refcounted status of type `%s`",
|
||||
str(using.type))
|
||||
if ipdltype.isMoveonly() != existingType.type.isMoveonly():
|
||||
self.error(using.loc, "inconsistent moveonly status of type `%s`",
|
||||
str(using.type))
|
||||
using.decl = existingType
|
||||
return
|
||||
using.decl = self.declare(
|
||||
|
|
|
@ -11,8 +11,8 @@ function start(){
|
|||
o196=document.getElementById('ifr32247').contentDocument.createElementNS('http:2000svg','altGlyph');
|
||||
o230=o185.cloneNode(true);
|
||||
tmp.id='ifr42257';
|
||||
tmp.addEventListener("load", start_dataiframe11);
|
||||
o230.ownerDocument.documentElement.appendChild(tmp);
|
||||
start_dataiframe11();
|
||||
//window.setTimeout('start_dataiframe11()',100);
|
||||
}function start_dataiframe11(){
|
||||
o232=o230.ownerDocument.getElementById('ifr42257').contentDocument.documentElement;
|
||||
|
|
|
@ -367,7 +367,16 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
|
||||
if (rfp) {
|
||||
rfp->BuildDisplayList(aBuilder, this, aLists);
|
||||
// We're the subdoc for <browser remote="true"> and it has
|
||||
// painted content. Display its shadow layer tree.
|
||||
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
|
||||
|
||||
nsPoint offset = aBuilder->ToReferenceFrame(this);
|
||||
nsRect bounds = this->EnsureInnerView()->GetBounds() + offset;
|
||||
clipState.ClipContentDescendants(bounds);
|
||||
|
||||
aLists.Content()->AppendToTop(
|
||||
MakeDisplayItem<nsDisplayRemote>(aBuilder, this));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -165,13 +165,8 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
{
|
||||
MOZ_ASSERT(aFrame,
|
||||
"makes no sense to have a shadow tree without a frame");
|
||||
MOZ_ASSERT(!mContainer ||
|
||||
IsTempLayerManager(aManager) ||
|
||||
mContainer->Manager() == aManager,
|
||||
"retaining manager changed out from under us ... HELP!");
|
||||
|
||||
if (IsTempLayerManager(aManager) ||
|
||||
(mContainer && mContainer->Manager() != aManager)) {
|
||||
if (IsTempLayerManager(aManager)) {
|
||||
// This can happen if aManager is a "temporary" manager, or if the
|
||||
// widget's layer manager changed out from under us. We need to
|
||||
// FIXME handle the former case somehow, probably with an API to
|
||||
|
@ -279,23 +274,6 @@ RenderFrameParent::TriggerRepaint()
|
|||
docFrame->InvalidateLayer(DisplayItemType::TYPE_REMOTE);
|
||||
}
|
||||
|
||||
void
|
||||
RenderFrameParent::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
nsSubDocumentFrame* aFrame,
|
||||
const nsDisplayListSet& aLists)
|
||||
{
|
||||
// We're the subdoc for <browser remote="true"> and it has
|
||||
// painted content. Display its shadow layer tree.
|
||||
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
|
||||
|
||||
nsPoint offset = aBuilder->ToReferenceFrame(aFrame);
|
||||
nsRect bounds = aFrame->EnsureInnerView()->GetBounds() + offset;
|
||||
clipState.ClipContentDescendants(bounds);
|
||||
|
||||
aLists.Content()->AppendToTop(
|
||||
MakeDisplayItem<nsDisplayRemote>(aBuilder, aFrame));
|
||||
}
|
||||
|
||||
void
|
||||
RenderFrameParent::GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier)
|
||||
{
|
||||
|
@ -346,6 +324,7 @@ RenderFrameParent::EnsureLayersConnected(CompositorOptions* aCompositorOptions)
|
|||
nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
|
||||
nsSubDocumentFrame* aFrame)
|
||||
: nsDisplayItem(aBuilder, aFrame)
|
||||
, mTabId{0}
|
||||
, mEventRegionsOverride(EventRegionsOverride::NoOverride)
|
||||
{
|
||||
bool frameIsPointerEventsNone =
|
||||
|
@ -357,6 +336,25 @@ nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
|
|||
if (nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(aFrame->PresShell())) {
|
||||
mEventRegionsOverride |= EventRegionsOverride::ForceDispatchToContent;
|
||||
}
|
||||
|
||||
nsFrameLoader* frameLoader = GetRenderFrameParent()->FrameLoader();
|
||||
if (frameLoader) {
|
||||
TabParent* browser = TabParent::GetFrom(frameLoader);
|
||||
if (browser) {
|
||||
mTabId = browser->GetTabId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::LayerState
|
||||
nsDisplayRemote::GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters)
|
||||
{
|
||||
if (mozilla::layout::IsTempLayerManager(aManager)) {
|
||||
return mozilla::LAYER_NONE;
|
||||
}
|
||||
return mozilla::LAYER_ACTIVE_FORCE;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -383,6 +381,21 @@ nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
return layer.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayRemote::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx)
|
||||
{
|
||||
DrawTarget* target = aCtx->GetDrawTarget();
|
||||
if (!target->IsRecording() || mTabId == 0) {
|
||||
NS_WARNING("Remote iframe not rendered");
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
Rect destRect =
|
||||
mozilla::NSRectToSnappedRect(GetContentRect(), appUnitsPerDevPixel, *target);
|
||||
target->DrawDependentSurface(mTabId, destRect);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayRemote::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
|
||||
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include <map>
|
||||
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/layers/APZUtils.h"
|
||||
#include "mozilla/layers/CompositorOptions.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
|
@ -64,9 +65,6 @@ public:
|
|||
bool IsInitted();
|
||||
void Destroy();
|
||||
|
||||
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
nsSubDocumentFrame* aFrame,
|
||||
const nsDisplayListSet& aLists);
|
||||
|
||||
already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame,
|
||||
|
@ -90,6 +88,11 @@ public:
|
|||
|
||||
LayerManager* AttachLayerManager();
|
||||
|
||||
nsFrameLoader* FrameLoader() const
|
||||
{
|
||||
return mFrameLoader;
|
||||
}
|
||||
|
||||
protected:
|
||||
void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
|
@ -113,7 +116,6 @@ private:
|
|||
CompositorOptions mCompositorOptions;
|
||||
|
||||
RefPtr<nsFrameLoader> mFrameLoader;
|
||||
RefPtr<ContainerLayer> mContainer;
|
||||
RefPtr<LayerManager> mLayerManager;
|
||||
|
||||
// True after Destroy() has been called, which is triggered
|
||||
|
@ -156,15 +158,14 @@ public:
|
|||
|
||||
LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters) override
|
||||
{
|
||||
return mozilla::LAYER_ACTIVE_FORCE;
|
||||
}
|
||||
const ContainerLayerParameters& aParameters) override;
|
||||
|
||||
already_AddRefed<Layer>
|
||||
BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters) override;
|
||||
|
||||
void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
|
||||
|
||||
bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
|
||||
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||
const StackingContextHelper& aSc,
|
||||
|
@ -179,6 +180,7 @@ private:
|
|||
mozilla::layers::LayersId GetRemoteLayersId() const;
|
||||
RenderFrameParent* GetRenderFrameParent() const;
|
||||
|
||||
mozilla::dom::TabId mTabId;
|
||||
mozilla::LayoutDeviceIntPoint mOffset;
|
||||
mozilla::layers::EventRegionsOverride mEventRegionsOverride;
|
||||
};
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
[encrypted-media-default-feature-policy.https.sub.html]
|
||||
expected: TIMEOUT
|
||||
[Default "encrypted-media" feature policy ["self"\] allows same-origin iframes.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Default "encrypted-media" feature policy ["self"\] disallows cross-origin iframes.]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,35 +1,16 @@
|
|||
[MediaStream-default-feature-policy.https.sub.html]
|
||||
expected: TIMEOUT
|
||||
[Default "microphone" feature policy ["self"\] allows the top-level document.]
|
||||
expected: FAIL
|
||||
|
||||
[Default "microphone" feature policy ["self"\] allows same-origin iframes.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Default "microphone" feature policy ["self"\] disallows cross-origin iframes.]
|
||||
expected: FAIL
|
||||
|
||||
[Feature policy "microphone" can be enabled in cross-origin iframes using "allow" attribute.]
|
||||
expected: FAIL
|
||||
|
||||
[Default "camera" feature policy ["self"\] allows the top-level document.]
|
||||
expected: FAIL
|
||||
|
||||
[Default "camera" feature policy ["self"\] allows same-origin iframes.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Default "camera" feature policy ["self"\] disallows cross-origin iframes.]
|
||||
expected: FAIL
|
||||
|
||||
[Feature policy "camera" can be enabled in cross-origin iframes using "allow" attribute.]
|
||||
expected: FAIL
|
||||
|
||||
[Default "camera; microphone" feature policy ["self"\] allows the top-level document.]
|
||||
expected: FAIL
|
||||
|
||||
[Default "camera; microphone" feature policy ["self"\] allows same-origin iframes.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Default "camera; microphone" feature policy ["self"\] disallows cross-origin iframes.]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -38,28 +19,18 @@
|
|||
|
||||
|
||||
[MediaStream-default-feature-policy.https.html]
|
||||
expected: TIMEOUT
|
||||
[Default "microphone" feature policy ["self"\] allows same-origin iframes.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Default "microphone" feature policy ["self"\] disallows cross-origin iframes.]
|
||||
expected: FAIL
|
||||
|
||||
[Feature policy "microphone" can be enabled in cross-origin iframes using "allow" attribute.]
|
||||
expected: FAIL
|
||||
|
||||
[Default "camera" feature policy ["self"\] allows same-origin iframes.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Default "camera" feature policy ["self"\] disallows cross-origin iframes.]
|
||||
expected: FAIL
|
||||
|
||||
[Feature policy "camera" can be enabled in cross-origin iframes using "allow" attribute.]
|
||||
expected: FAIL
|
||||
|
||||
[Default "camera; microphone" feature policy ["self"\] allows same-origin iframes.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Default "camera; microphone" feature policy ["self"\] disallows cross-origin iframes.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
[xmlhttprequest-sync-default-feature-policy.sub.html]
|
||||
expected: TIMEOUT
|
||||
[Default "sync-xhr" feature policy ["*"\] allows same-origin iframes.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Feature policy "sync-xhr" can be disabled in cross-origin iframes using "allow" attribute.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -69,3 +69,4 @@ skip-if = verify
|
|||
[test_threathit_report.html]
|
||||
skip-if = verify
|
||||
[test_fastblock_bug1477046.html]
|
||||
skip-if = (os == 'win' && os_version == "6.1") || (os == 'mac') # Bug 1495110
|
||||
|
|
|
@ -1904,6 +1904,24 @@
|
|||
</body>
|
||||
</method>
|
||||
|
||||
<method name="drawSnapshot">
|
||||
<parameter name="x"/>
|
||||
<parameter name="y"/>
|
||||
<parameter name="w"/>
|
||||
<parameter name="h"/>
|
||||
<parameter name="scale"/>
|
||||
<parameter name="backgroundColor"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (!this.frameLoader) {
|
||||
throw Components.Exception("No frame loader.",
|
||||
Cr.NS_ERROR_FAILURE);
|
||||
}
|
||||
return this.frameLoader.drawSnapshot(x, y, w, h, scale, backgroundColor);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="dropLinks">
|
||||
<parameter name="aLinksCount"/>
|
||||
<parameter name="aLinks"/>
|
||||
|
|
|
@ -108,6 +108,23 @@ nsTArray_base<Alloc, Copy>::UsesAutoArrayBuffer() const
|
|||
bool IsTwiceTheRequiredBytesRepresentableAsUint32(size_t aCapacity,
|
||||
size_t aElemSize);
|
||||
|
||||
template<class Alloc, class Copy>
|
||||
template<typename ActualAlloc>
|
||||
typename ActualAlloc::ResultTypeProxy
|
||||
nsTArray_base<Alloc, Copy>::ExtendCapacity(size_type aLength,
|
||||
size_type aCount,
|
||||
size_type aElemSize)
|
||||
{
|
||||
mozilla::CheckedInt<size_type> newLength = aLength;
|
||||
newLength += aCount;
|
||||
|
||||
if (!newLength.isValid()) {
|
||||
return ActualAlloc::FailureResult();
|
||||
}
|
||||
|
||||
return this->EnsureCapacity<ActualAlloc>(newLength.value(), aElemSize);
|
||||
}
|
||||
|
||||
template<class Alloc, class Copy>
|
||||
template<typename ActualAlloc>
|
||||
typename ActualAlloc::ResultTypeProxy
|
||||
|
@ -330,7 +347,7 @@ nsTArray_base<Alloc, Copy>::SwapFromEnd(index_type aStart,
|
|||
|
||||
template<class Alloc, class Copy>
|
||||
template<typename ActualAlloc>
|
||||
bool
|
||||
typename ActualAlloc::ResultTypeProxy
|
||||
nsTArray_base<Alloc, Copy>::InsertSlotsAt(index_type aIndex, size_type aCount,
|
||||
size_type aElemSize,
|
||||
size_t aElemAlign)
|
||||
|
@ -339,20 +356,15 @@ nsTArray_base<Alloc, Copy>::InsertSlotsAt(index_type aIndex, size_type aCount,
|
|||
InvalidArrayIndex_CRASH(aIndex, Length());
|
||||
}
|
||||
|
||||
size_type newLen = Length() + aCount;
|
||||
|
||||
EnsureCapacity<ActualAlloc>(newLen, aElemSize);
|
||||
|
||||
// Check for out of memory conditions
|
||||
if (Capacity() < newLen) {
|
||||
return false;
|
||||
if (!ActualAlloc::Successful(this->ExtendCapacity<ActualAlloc>(Length(), aCount, aElemSize))) {
|
||||
return ActualAlloc::FailureResult();
|
||||
}
|
||||
|
||||
// Move the existing elements as needed. Note that this will
|
||||
// change our mLength, so no need to call IncrementLength.
|
||||
ShiftData<ActualAlloc>(aIndex, 0, aCount, aElemSize, aElemAlign);
|
||||
|
||||
return true;
|
||||
return ActualAlloc::SuccessResult();
|
||||
}
|
||||
|
||||
// nsTArray_base::IsAutoArrayRestorer is an RAII class which takes
|
||||
|
|
|
@ -396,6 +396,17 @@ protected:
|
|||
typename ActualAlloc::ResultTypeProxy EnsureCapacity(size_type aCapacity,
|
||||
size_type aElemSize);
|
||||
|
||||
// Extend the storage to accommodate aCount extra elements.
|
||||
// @param aLength The current size of the array.
|
||||
// @param aCount The number of elements to add.
|
||||
// @param aElemSize The size of an array element.
|
||||
// @return False if insufficient memory is available or the new length
|
||||
// would overflow; true otherwise.
|
||||
template<typename ActualAlloc>
|
||||
typename ActualAlloc::ResultTypeProxy ExtendCapacity(size_type aLength,
|
||||
size_type aCount,
|
||||
size_type aElemSize);
|
||||
|
||||
// Tries to resize the storage to the minimum required amount. If this fails,
|
||||
// the array is left as-is.
|
||||
// @param aElemSize The size of an array element.
|
||||
|
@ -448,8 +459,9 @@ protected:
|
|||
// @param aElementSize the size of an array element.
|
||||
// @param aElemAlign the alignment in bytes of an array element.
|
||||
template<typename ActualAlloc>
|
||||
bool InsertSlotsAt(index_type aIndex, size_type aCount,
|
||||
size_type aElementSize, size_t aElemAlign);
|
||||
typename ActualAlloc::ResultTypeProxy
|
||||
InsertSlotsAt(index_type aIndex, size_type aCount,
|
||||
size_type aElementSize, size_t aElemAlign);
|
||||
|
||||
template<typename ActualAlloc, class Allocator>
|
||||
typename ActualAlloc::ResultTypeProxy
|
||||
|
@ -1761,8 +1773,8 @@ public:
|
|||
protected:
|
||||
template<typename ActualAlloc = Alloc>
|
||||
elem_type* AppendElements(size_type aCount) {
|
||||
if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
|
||||
Length() + aCount, sizeof(elem_type)))) {
|
||||
if (!ActualAlloc::Successful(this->template ExtendCapacity<ActualAlloc>(
|
||||
Length(), aCount, sizeof(elem_type)))) {
|
||||
return nullptr;
|
||||
}
|
||||
elem_type* elems = Elements() + Length();
|
||||
|
@ -2230,9 +2242,8 @@ protected:
|
|||
template<typename ActualAlloc = Alloc>
|
||||
elem_type* InsertElementsAt(index_type aIndex, size_type aCount)
|
||||
{
|
||||
if (!base_type::template InsertSlotsAt<ActualAlloc>(aIndex, aCount,
|
||||
sizeof(elem_type),
|
||||
MOZ_ALIGNOF(elem_type))) {
|
||||
if (!ActualAlloc::Successful(this->template InsertSlotsAt<ActualAlloc>(
|
||||
aIndex, aCount, sizeof(elem_type), MOZ_ALIGNOF(elem_type)))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -2455,9 +2466,8 @@ auto
|
|||
nsTArray_Impl<E, Alloc>::InsertElementsAt(index_type aIndex, size_type aCount,
|
||||
const Item& aItem) -> elem_type*
|
||||
{
|
||||
if (!base_type::template InsertSlotsAt<ActualAlloc>(aIndex, aCount,
|
||||
sizeof(elem_type),
|
||||
MOZ_ALIGNOF(elem_type))) {
|
||||
if (!ActualAlloc::Successful(this->template InsertSlotsAt<ActualAlloc>(
|
||||
aIndex, aCount, sizeof(elem_type), MOZ_ALIGNOF(elem_type)))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -2480,6 +2490,7 @@ nsTArray_Impl<E, Alloc>::InsertElementAt(index_type aIndex) -> elem_type*
|
|||
InvalidArrayIndex_CRASH(aIndex, Length());
|
||||
}
|
||||
|
||||
// Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK.
|
||||
if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
|
||||
Length() + 1, sizeof(elem_type)))) {
|
||||
return nullptr;
|
||||
|
@ -2500,6 +2511,7 @@ nsTArray_Impl<E, Alloc>::InsertElementAt(index_type aIndex, Item&& aItem) -> ele
|
|||
InvalidArrayIndex_CRASH(aIndex, Length());
|
||||
}
|
||||
|
||||
// Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK.
|
||||
if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
|
||||
Length() + 1, sizeof(elem_type)))) {
|
||||
return nullptr;
|
||||
|
@ -2516,8 +2528,8 @@ template<class Item, typename ActualAlloc>
|
|||
auto
|
||||
nsTArray_Impl<E, Alloc>::AppendElements(const Item* aArray, size_type aArrayLen) -> elem_type*
|
||||
{
|
||||
if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
|
||||
Length() + aArrayLen, sizeof(elem_type)))) {
|
||||
if (!ActualAlloc::Successful(this->template ExtendCapacity<ActualAlloc>(
|
||||
Length(), aArrayLen, sizeof(elem_type)))) {
|
||||
return nullptr;
|
||||
}
|
||||
index_type len = Length();
|
||||
|
@ -2539,8 +2551,8 @@ nsTArray_Impl<E, Alloc>::AppendElements(nsTArray_Impl<Item, Allocator>&& aArray)
|
|||
|
||||
index_type len = Length();
|
||||
index_type otherLen = aArray.Length();
|
||||
if (!Alloc::Successful(this->template EnsureCapacity<Alloc>(
|
||||
len + otherLen, sizeof(elem_type)))) {
|
||||
if (!Alloc::Successful(this->template ExtendCapacity<Alloc>(
|
||||
len, otherLen, sizeof(elem_type)))) {
|
||||
return nullptr;
|
||||
}
|
||||
copy_type::MoveNonOverlappingRegion(Elements() + len, aArray.Elements(), otherLen,
|
||||
|
@ -2556,6 +2568,7 @@ template<class Item, typename ActualAlloc>
|
|||
auto
|
||||
nsTArray_Impl<E, Alloc>::AppendElement(Item&& aItem) -> elem_type*
|
||||
{
|
||||
// Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK.
|
||||
if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
|
||||
Length() + 1, sizeof(elem_type)))) {
|
||||
return nullptr;
|
||||
|
|
|
@ -98,6 +98,7 @@ public:
|
|||
~nsTHashtable();
|
||||
|
||||
nsTHashtable(nsTHashtable<EntryType>&& aOther);
|
||||
nsTHashtable<EntryType>& operator=(nsTHashtable<EntryType>&& aOther);
|
||||
|
||||
/**
|
||||
* Return the generation number for the table. This increments whenever
|
||||
|
@ -405,6 +406,14 @@ nsTHashtable<EntryType>::nsTHashtable(nsTHashtable<EntryType>&& aOther)
|
|||
{
|
||||
}
|
||||
|
||||
template<class EntryType>
|
||||
nsTHashtable<EntryType>&
|
||||
nsTHashtable<EntryType>::operator=(nsTHashtable<EntryType>&& aOther)
|
||||
{
|
||||
mTable = std::move(aOther.mTable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class EntryType>
|
||||
nsTHashtable<EntryType>::~nsTHashtable()
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче