forked from mirrors/gecko-dev
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
e6b82618f4
164 changed files with 3229 additions and 60466 deletions
|
|
@ -2163,12 +2163,13 @@ Accessible::RemoveChild(Accessible* aChild)
|
|||
void
|
||||
Accessible::MoveChild(uint32_t aNewIndex, Accessible* aChild)
|
||||
{
|
||||
MOZ_ASSERT(aChild, "No child was given");
|
||||
MOZ_ASSERT(aChild->mParent == this, "A child from different subtree was given");
|
||||
MOZ_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
|
||||
MOZ_ASSERT(static_cast<uint32_t>(aChild->mIndexInParent) != aNewIndex,
|
||||
MOZ_DIAGNOSTIC_ASSERT(aChild, "No child was given");
|
||||
MOZ_DIAGNOSTIC_ASSERT(aChild->mParent == this, "A child from different subtree was given");
|
||||
MOZ_DIAGNOSTIC_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
|
||||
MOZ_DIAGNOSTIC_ASSERT(aChild->mParent->GetChildAt(aChild->mIndexInParent) == aChild, "Wrong index in parent");
|
||||
MOZ_DIAGNOSTIC_ASSERT(static_cast<uint32_t>(aChild->mIndexInParent) != aNewIndex,
|
||||
"No move, same index");
|
||||
MOZ_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given");
|
||||
MOZ_DIAGNOSTIC_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given");
|
||||
|
||||
RefPtr<AccHideEvent> hideEvent = new AccHideEvent(aChild, false);
|
||||
if (mDoc->Controller()->QueueMutationEvent(hideEvent)) {
|
||||
|
|
|
|||
|
|
@ -217,6 +217,8 @@ static int do_main(int argc, char* argv[], char* envp[])
|
|||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
sandbox::BrokerServices* brokerServices =
|
||||
sandboxing::GetInitializedBrokerServices();
|
||||
sandboxing::PermissionsService* permissionsService =
|
||||
sandboxing::GetPermissionsService();
|
||||
#if defined(MOZ_CONTENT_SANDBOX)
|
||||
if (!brokerServices) {
|
||||
Output("Couldn't initialize the broker services.\n");
|
||||
|
|
@ -224,6 +226,7 @@ static int do_main(int argc, char* argv[], char* envp[])
|
|||
}
|
||||
#endif
|
||||
config.sandboxBrokerServices = brokerServices;
|
||||
config.sandboxPermissionsService = permissionsService;
|
||||
#endif
|
||||
|
||||
#ifdef LIBFUZZER
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ function delayedStartupFinished(aWindow) {
|
|||
function someTabLoaded(aWindow) {
|
||||
return new Promise(function(resolve) {
|
||||
aWindow.gBrowser.addEventListener("load", function onLoad(aEvent) {
|
||||
if (aWindow.location === "about:blank") {
|
||||
if (aWindow.location.href === "about:blank") {
|
||||
return;
|
||||
}
|
||||
let tab = aWindow.gBrowser._getTabForContentWindow(
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
|
|||
# The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
|
||||
MAR_CHANNEL_ID=firefox-mozilla-central
|
||||
MOZ_PROFILE_MIGRATOR=1
|
||||
MOZ_WEBGL_CONFORMANT=1
|
||||
MOZ_JSDOWNLOADS=1
|
||||
MOZ_RUST_MP4PARSE=1
|
||||
|
||||
|
|
|
|||
|
|
@ -1290,7 +1290,7 @@ Inspector.prototype = {
|
|||
attributesSubmenu.append(new MenuItem({
|
||||
id: "node-menu-copy-attribute",
|
||||
label: INSPECTOR_L10N.getFormatStr("inspectorCopyAttributeValue.label",
|
||||
isAttributeClicked ? `"${nodeInfo.value}"` : ""),
|
||||
isAttributeClicked ? `${nodeInfo.value}` : ""),
|
||||
accesskey: INSPECTOR_L10N.getStr("inspectorCopyAttributeValue.accesskey"),
|
||||
disabled: !isAttributeClicked,
|
||||
click: () => this.onCopyAttributeValue(),
|
||||
|
|
@ -1298,7 +1298,7 @@ Inspector.prototype = {
|
|||
attributesSubmenu.append(new MenuItem({
|
||||
id: "node-menu-edit-attribute",
|
||||
label: INSPECTOR_L10N.getFormatStr("inspectorEditAttribute.label",
|
||||
isAttributeClicked ? `"${nodeInfo.name}"` : ""),
|
||||
isAttributeClicked ? `${nodeInfo.name}` : ""),
|
||||
accesskey: INSPECTOR_L10N.getStr("inspectorEditAttribute.accesskey"),
|
||||
disabled: !isAttributeClicked,
|
||||
click: () => this.onEditAttribute(),
|
||||
|
|
@ -1306,7 +1306,7 @@ Inspector.prototype = {
|
|||
attributesSubmenu.append(new MenuItem({
|
||||
id: "node-menu-remove-attribute",
|
||||
label: INSPECTOR_L10N.getFormatStr("inspectorRemoveAttribute.label",
|
||||
isAttributeClicked ? `"${nodeInfo.name}"` : ""),
|
||||
isAttributeClicked ? `${nodeInfo.name}` : ""),
|
||||
accesskey: INSPECTOR_L10N.getStr("inspectorRemoveAttribute.accesskey"),
|
||||
disabled: !isAttributeClicked,
|
||||
click: () => this.onRemoveAttribute(),
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
}
|
||||
|
||||
.accordion ._header:hover {
|
||||
background-color: var(--theme-selection-color);
|
||||
background-color: var(--theme-toolbar-hover);
|
||||
}
|
||||
|
||||
.accordion ._header:hover svg {
|
||||
|
|
|
|||
|
|
@ -67,11 +67,6 @@ function LayoutView(inspector, window) {
|
|||
this.onSidebarSelect = this.onSidebarSelect.bind(this);
|
||||
|
||||
this.init();
|
||||
|
||||
this.highlighters.on("grid-highlighter-hidden", this.onHighlighterChange);
|
||||
this.highlighters.on("grid-highlighter-shown", this.onHighlighterChange);
|
||||
this.inspector.selection.on("new-node-front", this.onNewSelection);
|
||||
this.inspector.sidebar.on("select", this.onSidebarSelect);
|
||||
}
|
||||
|
||||
LayoutView.prototype = {
|
||||
|
|
@ -89,6 +84,11 @@ LayoutView.prototype = {
|
|||
|
||||
this.loadHighlighterSettings();
|
||||
|
||||
this.highlighters.on("grid-highlighter-hidden", this.onHighlighterChange);
|
||||
this.highlighters.on("grid-highlighter-shown", this.onHighlighterChange);
|
||||
this.inspector.selection.on("new-node-front", this.onNewSelection);
|
||||
this.inspector.sidebar.on("select", this.onSidebarSelect);
|
||||
|
||||
// Create a shared SwatchColorPicker instance to be reused by all GridItem components.
|
||||
this.swatchColorPickerTooltip = new SwatchColorPickerTooltip(
|
||||
this.inspector.toolbox.doc,
|
||||
|
|
|
|||
|
|
@ -107,21 +107,21 @@ inspector.menu.selectElement.label=Select Element #%S
|
|||
# sub-menu "Attribute" in the inspector contextual-menu that appears
|
||||
# when the user right-clicks on the node in the inspector, and that allows
|
||||
# to edit an attribute on this node.
|
||||
inspectorEditAttribute.label=Edit Attribute %S
|
||||
inspectorEditAttribute.label=Edit Attribute “%S”
|
||||
inspectorEditAttribute.accesskey=E
|
||||
|
||||
# LOCALIZATION NOTE (inspectorRemoveAttribute.label): This is the label of a
|
||||
# sub-menu "Attribute" in the inspector contextual-menu that appears
|
||||
# when the user right-clicks on the attribute of a node in the inspector,
|
||||
# and that allows to remove this attribute.
|
||||
inspectorRemoveAttribute.label=Remove Attribute %S
|
||||
inspectorRemoveAttribute.label=Remove Attribute “%S”
|
||||
inspectorRemoveAttribute.accesskey=R
|
||||
|
||||
# LOCALIZATION NOTE (inspectorCopyAttributeValue.label): This is the label of a
|
||||
# sub-menu "Attribute" in the inspector contextual-menu that appears
|
||||
# when the user right-clicks on the attribute of a node in the inspector,
|
||||
# and that allows to copy the attribute value to clipboard.
|
||||
inspectorCopyAttributeValue.label=Copy Attribute Value %S
|
||||
inspectorCopyAttributeValue.label=Copy Attribute Value “%S”
|
||||
inspectorCopyAttributeValue.accesskey=V
|
||||
|
||||
# LOCALIZATION NOTE (inspector.nodePreview.selectNodeLabel):
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
.theme-dark {
|
||||
--rdm-box-shadow: 0 4px 4px 0 rgba(105, 105, 105, 0.26);
|
||||
--submit-button-active-background-color: var(--toolbar-tab-hover-active);
|
||||
--submit-button-active-background-color: var(--theme-toolbar-hover-active);
|
||||
--submit-button-active-color: var(--theme-selection-color);
|
||||
--viewport-color: #c6ccd0;
|
||||
--viewport-hover-color: #dde1e4;
|
||||
|
|
@ -536,7 +536,7 @@ select > option.divider {
|
|||
}
|
||||
|
||||
#device-submit-button:hover {
|
||||
background-color: var(--toolbar-tab-hover);
|
||||
background-color: var(--theme-toolbar-hover);
|
||||
}
|
||||
|
||||
#device-submit-button:hover:active {
|
||||
|
|
|
|||
|
|
@ -95,12 +95,12 @@
|
|||
|
||||
.theme-dark .tabs .tabs-menu-item:hover:not(.is-active),
|
||||
.theme-light .tabs .tabs-menu-item:hover:not(.is-active) {
|
||||
background-color: var(--toolbar-tab-hover);
|
||||
background-color: var(--theme-toolbar-hover);
|
||||
}
|
||||
|
||||
.theme-dark .tabs .tabs-menu-item:hover:active:not(.is-active),
|
||||
.theme-light .tabs .tabs-menu-item:hover:active:not(.is-active) {
|
||||
background-color: var(--toolbar-tab-hover-active);
|
||||
background-color: var(--theme-toolbar-hover-active);
|
||||
}
|
||||
|
||||
.theme-dark .tabs .tabs-menu-item.is-active,
|
||||
|
|
@ -165,7 +165,7 @@
|
|||
}
|
||||
|
||||
.theme-firebug .tabs .tabs-menu-item:hover:active a {
|
||||
background-color: var(--toolbar-tab-hover-active);
|
||||
background-color: var(--theme-toolbar-hover-active);
|
||||
}
|
||||
|
||||
.theme-firebug .tabs .tabs-menu-item.is-active:hover:active a {
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
/* CSS Variables specific to the devtools toolbar that aren't defined by the themes */
|
||||
.theme-light {
|
||||
--toolbar-tab-hover: rgba(170, 170, 170, .2);
|
||||
--toolbar-tab-hover-active: rgba(170, 170, 170, .4);
|
||||
--searchbox-background-color: #ffee99;
|
||||
--searchbox-border-color: #ffbf00;
|
||||
--searcbox-no-match-background-color: #ffe5e5;
|
||||
|
|
@ -19,8 +17,6 @@
|
|||
}
|
||||
|
||||
.theme-dark {
|
||||
--toolbar-tab-hover: rgba(110,120,130,0.1);
|
||||
--toolbar-tab-hover-active: rgba(110,120,130,0.2);
|
||||
--searchbox-background-color: #4d4222;
|
||||
--searchbox-border-color: #d99f2b;
|
||||
--searcbox-no-match-background-color: #402325;
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@
|
|||
}
|
||||
|
||||
.devtools-tab:hover {
|
||||
background-color: var(--toolbar-tab-hover);
|
||||
background-color: var(--theme-toolbar-hover);
|
||||
}
|
||||
|
||||
.theme-dark .devtools-tab:hover:active {
|
||||
|
|
@ -142,7 +142,7 @@
|
|||
}
|
||||
|
||||
.devtools-tab:hover:active {
|
||||
background-color: var(--toolbar-tab-hover-active);
|
||||
background-color: var(--theme-toolbar-hover-active);
|
||||
}
|
||||
|
||||
.theme-dark .devtools-tab:not(.selected).highlighted {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
--theme-tab-toolbar-background: #fcfcfc;
|
||||
--theme-toolbar-background: #fcfcfc;
|
||||
--theme-toolbar-hover: rgba(170, 170, 170, .2);
|
||||
--theme-toolbar-hover-active: rgba(170, 170, 170, .4);
|
||||
--theme-selection-background: #4c9ed9;
|
||||
--theme-selection-background-semitransparent: rgba(76, 158, 217, 0.15);
|
||||
--theme-selection-color: #f5f7fa;
|
||||
|
|
@ -81,6 +83,8 @@
|
|||
|
||||
--theme-tab-toolbar-background: #272b35;
|
||||
--theme-toolbar-background: #272b35;
|
||||
--theme-toolbar-hover: rgba(110, 120, 130, 0.1);
|
||||
--theme-toolbar-hover-active: rgba(110, 120, 130, 0.2);
|
||||
--theme-selection-background: #5675B9;
|
||||
--theme-selection-background-semitransparent: rgba(86, 117, 185, 0.5);
|
||||
--theme-selection-color: #f5f7fa;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,14 @@ class UnionMember
|
|||
{
|
||||
AlignedStorage2<T> mStorage;
|
||||
|
||||
// Copy construction can't be supported because C++ requires that any enclosed
|
||||
// T be initialized in a way C++ knows about -- that is, by |new| or similar.
|
||||
UnionMember(const UnionMember&) = delete;
|
||||
|
||||
public:
|
||||
UnionMember() = default;
|
||||
~UnionMember() = default;
|
||||
|
||||
T& SetValue()
|
||||
{
|
||||
new (mStorage.addr()) T();
|
||||
|
|
|
|||
|
|
@ -36,22 +36,13 @@ GetCanvasContextType(const nsAString& str, dom::CanvasContextType* const out_typ
|
|||
return true;
|
||||
}
|
||||
|
||||
if (str.EqualsLiteral("experimental-webgl")) {
|
||||
if (str.EqualsLiteral("webgl") ||
|
||||
str.EqualsLiteral("experimental-webgl"))
|
||||
{
|
||||
*out_type = dom::CanvasContextType::WebGL1;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WEBGL_CONFORMANT
|
||||
if (str.EqualsLiteral("webgl")) {
|
||||
/* WebGL 1.0, $2.1 "Context Creation":
|
||||
* If the user agent supports both the webgl and experimental-webgl
|
||||
* canvas context types, they shall be treated as aliases.
|
||||
*/
|
||||
*out_type = dom::CanvasContextType::WebGL1;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (WebGL2Context::IsSupported()) {
|
||||
if (str.EqualsLiteral("webgl2")) {
|
||||
*out_type = dom::CanvasContextType::WebGL2;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/dom/FileCreatorHelper.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
|
@ -60,6 +61,7 @@ File::CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer,
|
|||
/* static */ already_AddRefed<File>
|
||||
File::CreateFromFile(nsISupports* aParent, nsIFile* aFile)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
|
||||
RefPtr<File> file = new File(aParent, new FileBlobImpl(aFile));
|
||||
return file.forget();
|
||||
}
|
||||
|
|
@ -68,6 +70,7 @@ File::CreateFromFile(nsISupports* aParent, nsIFile* aFile)
|
|||
File::CreateFromFile(nsISupports* aParent, nsIFile* aFile,
|
||||
const nsAString& aName, const nsAString& aContentType)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
|
||||
RefPtr<File> file = new File(aParent,
|
||||
new FileBlobImpl(aFile, aName, aContentType));
|
||||
return file.forget();
|
||||
|
|
@ -166,8 +169,6 @@ File::CreateFromNsIFile(const GlobalObject& aGlobal,
|
|||
SystemCallerGuarantee aGuarantee,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
|
||||
RefPtr<Promise> promise =
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ FileBlobImpl::FileBlobImpl(nsIFile* aFile)
|
|||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
// Lazily get the content type and size
|
||||
mContentType.SetIsVoid(true);
|
||||
mFile->GetLeafName(mName);
|
||||
|
|
@ -41,6 +42,7 @@ FileBlobImpl::FileBlobImpl(const nsAString& aName,
|
|||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
}
|
||||
|
||||
FileBlobImpl::FileBlobImpl(const nsAString& aName,
|
||||
|
|
@ -52,6 +54,7 @@ FileBlobImpl::FileBlobImpl(const nsAString& aName,
|
|||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
}
|
||||
|
||||
FileBlobImpl::FileBlobImpl(nsIFile* aFile, const nsAString& aName,
|
||||
|
|
@ -61,6 +64,7 @@ FileBlobImpl::FileBlobImpl(nsIFile* aFile, const nsAString& aName,
|
|||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
if (aContentType.IsEmpty()) {
|
||||
// Lazily get the content type and size
|
||||
mContentType.SetIsVoid(true);
|
||||
|
|
@ -74,6 +78,7 @@ FileBlobImpl::FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart,
|
|||
, mWholeFile(false)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
mImmutable = aOther->mImmutable;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ FileCreatorHelper::CreateFile(nsIGlobalObject* aGlobalObject,
|
|||
bool aIsFromNsIFile,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<Promise> promise = Promise::Create(aGlobalObject, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ var testRanCounter = 0;
|
|||
var expectedTestCount = 0;
|
||||
|
||||
function testHasRun() {
|
||||
//alert(testRanCounter);
|
||||
++testRanCounter;
|
||||
if (testRanCounter == expectedTestCount) {
|
||||
SimpleTest.finish();
|
||||
|
|
@ -118,14 +117,6 @@ function convertXHRBinary(s) {
|
|||
return res;
|
||||
}
|
||||
|
||||
function testHasRun() {
|
||||
//alert(testRanCounter);
|
||||
++testRanCounter;
|
||||
if (testRanCounter == expectedTestCount) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
function gc() {
|
||||
window.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
|
||||
.getInterface(SpecialPowers.Ci.nsIDOMWindowUtils)
|
||||
|
|
|
|||
|
|
@ -88,9 +88,7 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ProcessHangMonitor.h"
|
||||
#include "mozilla/ProcessHangMonitorIPC.h"
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
#include "mozilla/ProfileGatherer.h"
|
||||
#endif
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
|
@ -267,9 +265,6 @@ extern const char* kForceEnableE10sPref;
|
|||
|
||||
using base::ChildPrivileges;
|
||||
using base::KillProcess;
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
using mozilla::ProfileGatherer;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
using namespace CrashReporter;
|
||||
|
|
@ -1201,10 +1196,7 @@ ContentParent::Init()
|
|||
rv = profiler->GetStartParams(getter_AddRefs(currentProfilerParams));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
nsCOMPtr<nsISupports> gatherer;
|
||||
rv = profiler->GetProfileGatherer(getter_AddRefs(gatherer));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
mGatherer = static_cast<ProfileGatherer*>(gatherer.get());
|
||||
mIsProfilerActive = true;
|
||||
|
||||
StartProfiler(currentProfilerParams);
|
||||
}
|
||||
|
|
@ -1589,8 +1581,8 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
|||
mConsoleService = nullptr;
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
if (mGatherer && !mProfile.IsEmpty()) {
|
||||
mGatherer->OOPExitProfile(mProfile);
|
||||
if (mIsProfilerActive && !mProfile.IsEmpty()) {
|
||||
profiler_OOP_exit_profile(mProfile);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -1828,24 +1820,6 @@ ContentParent::GetTestShellSingleton()
|
|||
return static_cast<TestShellParent*>(p);
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::InitializeMembers()
|
||||
{
|
||||
mSubprocess = nullptr;
|
||||
mChildID = gContentChildID++;
|
||||
mGeolocationWatchID = -1;
|
||||
mNumDestroyingTabs = 0;
|
||||
mIsAvailable = true;
|
||||
mIsAlive = true;
|
||||
mSendPermissionUpdates = false;
|
||||
mCalledClose = false;
|
||||
mCalledKillHard = false;
|
||||
mCreatedPairedMinidumps = false;
|
||||
mShutdownPending = false;
|
||||
mIPCOpen = true;
|
||||
mHangMonitorActor = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PRIORITY_FOREGROUND */)
|
||||
{
|
||||
|
|
@ -1934,13 +1908,27 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
|
|||
ContentParent::ContentParent(ContentParent* aOpener,
|
||||
const nsAString& aRemoteType)
|
||||
: nsIContentParent()
|
||||
, mSubprocess(nullptr)
|
||||
, mLaunchTS(TimeStamp::Now())
|
||||
, mOpener(aOpener)
|
||||
, mRemoteType(aRemoteType)
|
||||
, mChildID(gContentChildID++)
|
||||
, mGeolocationWatchID(-1)
|
||||
, mNumDestroyingTabs(0)
|
||||
, mIsAvailable(true)
|
||||
, mIsAlive(true)
|
||||
, mSendPermissionUpdates(false)
|
||||
, mIsForBrowser(!mRemoteType.IsEmpty())
|
||||
, mCalledClose(false)
|
||||
, mCalledKillHard(false)
|
||||
, mCreatedPairedMinidumps(false)
|
||||
, mShutdownPending(false)
|
||||
, mIPCOpen(true)
|
||||
, mHangMonitorActor(nullptr)
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
, mIsProfilerActive(false)
|
||||
#endif
|
||||
{
|
||||
InitializeMembers(); // Perform common initialization.
|
||||
|
||||
// Insert ourselves into the global linked list of ContentParent objects.
|
||||
if (!sContentParents) {
|
||||
sContentParents = new LinkedList<ContentParent>();
|
||||
|
|
@ -2578,8 +2566,8 @@ ContentParent::Observe(nsISupports* aSubject,
|
|||
#ifdef MOZ_GECKO_PROFILER
|
||||
// Need to do this before the mIsAlive check to avoid missing profiles.
|
||||
if (!strcmp(aTopic, "profiler-subprocess-gather")) {
|
||||
if (mGatherer) {
|
||||
mGatherer->WillGatherOOPProfile();
|
||||
if (mIsProfilerActive) {
|
||||
profiler_will_gather_OOP_profile();
|
||||
if (mIsAlive && mSubprocess) {
|
||||
Unused << SendGatherProfile();
|
||||
}
|
||||
|
|
@ -2691,7 +2679,7 @@ ContentParent::Observe(nsISupports* aSubject,
|
|||
StartProfiler(params);
|
||||
}
|
||||
else if (!strcmp(aTopic, "profiler-stopped")) {
|
||||
mGatherer = nullptr;
|
||||
mIsProfilerActive = false;
|
||||
Unused << SendStopProfiler();
|
||||
}
|
||||
else if (!strcmp(aTopic, "profiler-paused")) {
|
||||
|
|
@ -4543,11 +4531,11 @@ mozilla::ipc::IPCResult
|
|||
ContentParent::RecvProfile(const nsCString& aProfile)
|
||||
{
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
if (NS_WARN_IF(!mGatherer)) {
|
||||
if (NS_WARN_IF(!mIsProfilerActive)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
mProfile = aProfile;
|
||||
mGatherer->GatheredOOPProfile();
|
||||
profiler_gathered_OOP_profile();
|
||||
#endif
|
||||
return IPC_OK();
|
||||
}
|
||||
|
|
@ -4679,9 +4667,7 @@ ContentParent::StartProfiler(nsIProfilerStartParams* aParams)
|
|||
if (NS_WARN_IF(!profiler)) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsISupports> gatherer;
|
||||
profiler->GetProfileGatherer(getter_AddRefs(gatherer));
|
||||
mGatherer = static_cast<ProfileGatherer*>(gatherer.get());
|
||||
mIsProfilerActive = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,9 +54,6 @@ class nsIWidget;
|
|||
|
||||
namespace mozilla {
|
||||
class PRemoteSpellcheckEngineParent;
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
class ProfileGatherer;
|
||||
#endif
|
||||
|
||||
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
class SandboxBroker;
|
||||
|
|
@ -675,9 +672,6 @@ private:
|
|||
ContentParent(ContentParent* aOpener,
|
||||
const nsAString& aRemoteType);
|
||||
|
||||
// The common initialization for the constructors.
|
||||
void InitializeMembers();
|
||||
|
||||
// Launch the subprocess and associated initialization.
|
||||
// Returns false if the process fails to start.
|
||||
bool LaunchSubprocess(hal::ProcessPriority aInitialPriority = hal::PROCESS_PRIORITY_FOREGROUND);
|
||||
|
|
@ -1191,7 +1185,7 @@ private:
|
|||
PProcessHangMonitorParent* mHangMonitorActor;
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
RefPtr<mozilla::ProfileGatherer> mGatherer;
|
||||
bool mIsProfilerActive;
|
||||
#endif
|
||||
nsCString mProfile;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "mediasink/OutputStreamManager.h"
|
||||
#include "mediasink/VideoSink.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/IndexSequence.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
|
@ -29,6 +30,7 @@
|
|||
#include "mozilla/SizePrintfMacros.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/TaskQueue.h"
|
||||
#include "mozilla/Tuple.h"
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
|
@ -284,17 +286,35 @@ protected:
|
|||
MediaQueue<MediaData>& AudioQueue() const { return mMaster->mAudioQueue; }
|
||||
MediaQueue<MediaData>& VideoQueue() const { return mMaster->mVideoQueue; }
|
||||
|
||||
template <class S, typename... Args, size_t... Indexes>
|
||||
auto
|
||||
CallEnterMemberFunction(S* aS,
|
||||
Tuple<Args...>& aTuple,
|
||||
IndexSequence<Indexes...>)
|
||||
-> decltype(ReturnTypeHelper(&S::Enter))
|
||||
{
|
||||
return aS->Enter(Move(Get<Indexes>(aTuple))...);
|
||||
}
|
||||
|
||||
// Note this function will delete the current state object.
|
||||
// Don't access members to avoid UAF after this call.
|
||||
template <class S, typename... Ts>
|
||||
auto SetState(Ts... aArgs)
|
||||
auto SetState(Ts&&... aArgs)
|
||||
-> decltype(ReturnTypeHelper(&S::Enter))
|
||||
{
|
||||
// |aArgs| must be passed by reference to avoid passing MOZ_NON_PARAM class
|
||||
// SeekJob by value. See bug 1287006 and bug 1338374. But we still *must*
|
||||
// copy the parameters, because |Exit()| can modify them. See bug 1312321.
|
||||
// So we 1) pass the parameters by reference, but then 2) immediately copy
|
||||
// them into a Tuple to be safe against modification, and finally 3) move
|
||||
// the elements of the Tuple into the final function call.
|
||||
auto copiedArgs = MakeTuple(Forward<Ts>(aArgs)...);
|
||||
|
||||
// keep mMaster in a local object because mMaster will become invalid after
|
||||
// the current state object is deleted.
|
||||
auto master = mMaster;
|
||||
|
||||
auto s = new S(master);
|
||||
auto* s = new S(master);
|
||||
|
||||
MOZ_ASSERT(GetState() != s->GetState()
|
||||
|| GetState() == DECODER_STATE_SEEKING);
|
||||
|
|
@ -304,7 +324,8 @@ protected:
|
|||
Exit();
|
||||
|
||||
master->mStateObj.reset(s);
|
||||
return s->Enter(Move(aArgs)...);
|
||||
return CallEnterMemberFunction(s, copiedArgs,
|
||||
typename IndexSequenceFor<Ts...>::Type());
|
||||
}
|
||||
|
||||
RefPtr<MediaDecoder::SeekPromise>
|
||||
|
|
@ -904,7 +925,7 @@ class MediaDecoderStateMachine::SeekingState
|
|||
public:
|
||||
explicit SeekingState(Master* aPtr) : StateObject(aPtr) { }
|
||||
|
||||
RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob aSeekJob,
|
||||
RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob&& aSeekJob,
|
||||
EventVisibility aVisibility)
|
||||
{
|
||||
mSeekJob = Move(aSeekJob);
|
||||
|
|
@ -982,7 +1003,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob aSeekJob,
|
||||
RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob&& aSeekJob,
|
||||
EventVisibility aVisibility)
|
||||
{
|
||||
MOZ_ASSERT(aSeekJob.mTarget->IsAccurate() || aSeekJob.mTarget->IsFast());
|
||||
|
|
@ -1441,7 +1462,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob aSeekJob,
|
||||
RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob&& aSeekJob,
|
||||
EventVisibility aVisibility)
|
||||
{
|
||||
MOZ_ASSERT(aSeekJob.mTarget->IsNextFrame());
|
||||
|
|
|
|||
|
|
@ -257,10 +257,9 @@ GMPVideoEncoderParent::ActorDestroy(ActorDestroyReason aWhy)
|
|||
// Must be shut down before VideoEncoderDestroyed(), since this can recurse
|
||||
// the GMPThread event loop. See bug 1049501
|
||||
if (mEncodedThread) {
|
||||
// Can't get it to allow me to use WrapRunnable with a nsCOMPtr<nsIThread>()
|
||||
NS_DispatchToMainThread(
|
||||
WrapRunnableNM<decltype(&ShutdownEncodedThread),
|
||||
nsCOMPtr<nsIThread> >(&ShutdownEncodedThread, mEncodedThread));
|
||||
WrapRunnableNM(&ShutdownEncodedThread, nsCOMPtr<nsIThread>(mEncodedThread))
|
||||
);
|
||||
mEncodedThread = nullptr;
|
||||
}
|
||||
if (mPlugin) {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class DelayedResolveOrReject : public Runnable
|
|||
public:
|
||||
DelayedResolveOrReject(TaskQueue* aTaskQueue,
|
||||
TestPromise::Private* aPromise,
|
||||
TestPromise::ResolveOrRejectValue aValue,
|
||||
const TestPromise::ResolveOrRejectValue& aValue,
|
||||
int aIterations)
|
||||
: mTaskQueue(aTaskQueue)
|
||||
, mPromise(aPromise)
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
|||
}
|
||||
|
||||
void
|
||||
SourceBuffer::AppendDataCompletedWithSuccess(SourceBufferTask::AppendBufferResult aResult)
|
||||
SourceBuffer::AppendDataCompletedWithSuccess(const SourceBufferTask::AppendBufferResult& aResult)
|
||||
{
|
||||
MOZ_ASSERT(mUpdating);
|
||||
mPendingAppend.Complete();
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ private:
|
|||
uint32_t aLength,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void AppendDataCompletedWithSuccess(SourceBufferTask::AppendBufferResult aResult);
|
||||
void AppendDataCompletedWithSuccess(const SourceBufferTask::AppendBufferResult& aResult);
|
||||
void AppendDataErrored(const MediaResult& aError);
|
||||
|
||||
RefPtr<MediaSource> mMediaSource;
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ SpeechSynthesisUtterance::GetChosenVoiceURI(nsString& aResult) const
|
|||
void
|
||||
SpeechSynthesisUtterance::DispatchSpeechSynthesisEvent(const nsAString& aEventType,
|
||||
uint32_t aCharIndex,
|
||||
Nullable<uint32_t> aCharLength,
|
||||
const Nullable<uint32_t>& aCharLength,
|
||||
float aElapsedTime,
|
||||
const nsAString& aName)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ private:
|
|||
|
||||
void DispatchSpeechSynthesisEvent(const nsAString& aEventType,
|
||||
uint32_t aCharIndex,
|
||||
Nullable<uint32_t> aCharLength,
|
||||
const Nullable<uint32_t>& aCharLength,
|
||||
float aElapsedTime, const nsAString& aName);
|
||||
|
||||
nsString mText;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
|
|||
using class mac_plugin_interposing::NSCursorInfo from "mozilla/plugins/PluginMessageUtils.h";
|
||||
using struct nsID from "nsID.h";
|
||||
using struct mozilla::plugins::NPAudioDeviceChangeDetailsIPC from "mozilla/plugins/PluginMessageUtils.h";
|
||||
using mozilla::plugins::GetFileNameFunc from "mozilla/plugins/PluginMessageUtils.h";
|
||||
using mozilla::plugins::OpenFileNameIPC from "mozilla/plugins/PluginMessageUtils.h";
|
||||
using mozilla::plugins::OpenFileNameRetIPC from "mozilla/plugins/PluginMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
|
|
@ -163,6 +166,10 @@ parent:
|
|||
|
||||
intr NPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(bool shouldRegister)
|
||||
returns (NPError result);
|
||||
|
||||
// Used to broker the GetOpenFileName/GetSaveFileName file pickers on Windows.
|
||||
intr GetFileName(GetFileNameFunc aFunc, OpenFileNameIPC aOfnIn)
|
||||
returns (OpenFileNameRetIPC aOfnOut, bool aResult);
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
|
|
|
|||
|
|
@ -151,5 +151,192 @@ void DeferNPVariantLastRelease(const NPNetscapeFuncs* f, NPVariant* v)
|
|||
VOID_TO_NPVARIANT(*v);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
void
|
||||
OpenFileNameIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn)
|
||||
{
|
||||
mHwndOwner = nullptr;
|
||||
|
||||
// Filter is double-NULL terminated. mFilter should include the double-NULL.
|
||||
mHasFilter = aLpofn->lpstrFilter != nullptr;
|
||||
if (mHasFilter) {
|
||||
uint32_t dNullIdx = 0;
|
||||
while (aLpofn->lpstrFilter[dNullIdx] != L'\0' ||
|
||||
aLpofn->lpstrFilter[dNullIdx+1] != L'\0') {
|
||||
dNullIdx++;
|
||||
}
|
||||
mFilter.assign(aLpofn->lpstrFilter, dNullIdx+2);
|
||||
}
|
||||
mHasCustomFilter = aLpofn->lpstrCustomFilter != nullptr;
|
||||
if (mHasCustomFilter) {
|
||||
mCustomFilterIn = std::wstring(aLpofn->lpstrCustomFilter);
|
||||
mNMaxCustFilterOut =
|
||||
aLpofn->nMaxCustFilter - (wcslen(aLpofn->lpstrCustomFilter) + 1);
|
||||
}
|
||||
else {
|
||||
mNMaxCustFilterOut = 0;
|
||||
}
|
||||
mFilterIndex = aLpofn->nFilterIndex;
|
||||
mFile = std::wstring(aLpofn->lpstrFile);
|
||||
mNMaxFile = aLpofn->nMaxFile;
|
||||
mNMaxFileTitle =
|
||||
aLpofn->lpstrFileTitle != nullptr ? aLpofn->nMaxFileTitle : 0;
|
||||
mHasInitialDir = aLpofn->lpstrInitialDir != nullptr;
|
||||
if (mHasInitialDir) {
|
||||
mInitialDir = std::wstring(aLpofn->lpstrInitialDir);
|
||||
}
|
||||
mHasTitle = aLpofn->lpstrTitle != nullptr;
|
||||
if (mHasTitle) {
|
||||
mTitle = std::wstring(aLpofn->lpstrTitle);
|
||||
}
|
||||
mHasDefExt = aLpofn->lpstrDefExt != nullptr;
|
||||
if (mHasDefExt) {
|
||||
mDefExt = std::wstring(aLpofn->lpstrDefExt);
|
||||
}
|
||||
|
||||
mFlags = aLpofn->Flags;
|
||||
// If the user sets OFN_ALLOWMULTISELECT then we require OFN_EXPLORER
|
||||
// as well. Without OFN_EXPLORER, the method has ancient legacy
|
||||
// behavior that we don't support.
|
||||
MOZ_ASSERT((mFlags & OFN_EXPLORER) || !(mFlags & OFN_ALLOWMULTISELECT));
|
||||
|
||||
// We ignore any visual customization and callbacks that the user set.
|
||||
mFlags &= ~(OFN_ENABLEHOOK | OFN_ENABLETEMPLATEHANDLE | OFN_ENABLETEMPLATE);
|
||||
|
||||
mFlagsEx = aLpofn->FlagsEx;
|
||||
}
|
||||
|
||||
void
|
||||
OpenFileNameIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const
|
||||
{
|
||||
aLpofn->lStructSize = sizeof(OPENFILENAMEW);
|
||||
aLpofn->hwndOwner = mHwndOwner;
|
||||
if (mHasFilter) {
|
||||
memcpy(const_cast<LPWSTR>(aLpofn->lpstrFilter),
|
||||
mFilter.data(), mFilter.size() * sizeof(wchar_t));
|
||||
}
|
||||
if (mHasCustomFilter) {
|
||||
aLpofn->nMaxCustFilter = mCustomFilterIn.size() + 1 + mNMaxCustFilterOut;
|
||||
wcscpy(aLpofn->lpstrCustomFilter, mCustomFilterIn.c_str());
|
||||
memset(aLpofn->lpstrCustomFilter + mCustomFilterIn.size() + 1, 0,
|
||||
mNMaxCustFilterOut * sizeof(wchar_t));
|
||||
}
|
||||
else {
|
||||
aLpofn->nMaxCustFilter = 0;
|
||||
}
|
||||
aLpofn->nFilterIndex = mFilterIndex;
|
||||
wcscpy(aLpofn->lpstrFile, mFile.c_str());
|
||||
aLpofn->nMaxFile = mNMaxFile;
|
||||
aLpofn->nMaxFileTitle = mNMaxFileTitle;
|
||||
if (mHasInitialDir) {
|
||||
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrInitialDir), mInitialDir.c_str());
|
||||
}
|
||||
if (mHasTitle) {
|
||||
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrTitle), mTitle.c_str());
|
||||
}
|
||||
aLpofn->Flags = mFlags; /* TODO: Consider adding OFN_NOCHANGEDIR */
|
||||
if (mHasDefExt) {
|
||||
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrDefExt), mDefExt.c_str());
|
||||
}
|
||||
aLpofn->FlagsEx = mFlagsEx;
|
||||
}
|
||||
|
||||
void
|
||||
OpenFileNameIPC::AllocateOfnStrings(LPOPENFILENAMEW aLpofn) const
|
||||
{
|
||||
if (mHasFilter) {
|
||||
// mFilter is double-NULL terminated and it includes the double-NULL in its length.
|
||||
aLpofn->lpstrFilter =
|
||||
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mFilter.size())));
|
||||
}
|
||||
if (mHasCustomFilter) {
|
||||
aLpofn->lpstrCustomFilter =
|
||||
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * (mCustomFilterIn.size() + 1) + mNMaxCustFilterOut));
|
||||
}
|
||||
aLpofn->lpstrFile =
|
||||
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFile));
|
||||
if (mNMaxFileTitle > 0) {
|
||||
aLpofn->lpstrFileTitle =
|
||||
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFileTitle));
|
||||
}
|
||||
if (mHasInitialDir) {
|
||||
aLpofn->lpstrInitialDir =
|
||||
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mInitialDir.size() + 1)));
|
||||
}
|
||||
if (mHasTitle) {
|
||||
aLpofn->lpstrTitle =
|
||||
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mTitle.size() + 1)));
|
||||
}
|
||||
if (mHasDefExt) {
|
||||
aLpofn->lpstrDefExt =
|
||||
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mDefExt.size() + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OpenFileNameIPC::FreeOfnStrings(LPOPENFILENAMEW aLpofn) const
|
||||
{
|
||||
if (aLpofn->lpstrFilter) {
|
||||
free(const_cast<LPWSTR>(aLpofn->lpstrFilter));
|
||||
}
|
||||
if (aLpofn->lpstrCustomFilter) {
|
||||
free(aLpofn->lpstrCustomFilter);
|
||||
}
|
||||
if (aLpofn->lpstrFile) {
|
||||
free(aLpofn->lpstrFile);
|
||||
}
|
||||
if (aLpofn->lpstrFileTitle) {
|
||||
free(aLpofn->lpstrFileTitle);
|
||||
}
|
||||
if (aLpofn->lpstrInitialDir) {
|
||||
free(const_cast<LPWSTR>(aLpofn->lpstrInitialDir));
|
||||
}
|
||||
if (aLpofn->lpstrTitle) {
|
||||
free(const_cast<LPWSTR>(aLpofn->lpstrTitle));
|
||||
}
|
||||
if (aLpofn->lpstrDefExt) {
|
||||
free(const_cast<LPWSTR>(aLpofn->lpstrDefExt));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OpenFileNameRetIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn)
|
||||
{
|
||||
if (aLpofn->lpstrCustomFilter != nullptr) {
|
||||
mCustomFilterOut =
|
||||
std::wstring(aLpofn->lpstrCustomFilter + wcslen(aLpofn->lpstrCustomFilter) + 1);
|
||||
}
|
||||
mFile.assign(aLpofn->lpstrFile, aLpofn->nMaxFile);
|
||||
if (aLpofn->lpstrFileTitle != nullptr) {
|
||||
mFileTitle.assign(aLpofn->lpstrFileTitle, wcslen(aLpofn->lpstrFileTitle) + 1);
|
||||
}
|
||||
mFileOffset = aLpofn->nFileOffset;
|
||||
mFileExtension = aLpofn->nFileExtension;
|
||||
}
|
||||
|
||||
void
|
||||
OpenFileNameRetIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const
|
||||
{
|
||||
if (aLpofn->lpstrCustomFilter) {
|
||||
LPWSTR secondString =
|
||||
aLpofn->lpstrCustomFilter + wcslen(aLpofn->lpstrCustomFilter) + 1;
|
||||
const wchar_t* customFilterOut = mCustomFilterOut.c_str();
|
||||
MOZ_ASSERT(wcslen(aLpofn->lpstrCustomFilter) + 1 +
|
||||
wcslen(customFilterOut) + 1 + 1 <= aLpofn->nMaxCustFilter);
|
||||
wcscpy(secondString, customFilterOut);
|
||||
secondString[wcslen(customFilterOut) + 1] = L'\0'; // terminated with two NULLs
|
||||
}
|
||||
MOZ_ASSERT(mFile.size() <= aLpofn->nMaxFile);
|
||||
memcpy(aLpofn->lpstrFile,
|
||||
mFile.data(), mFile.size() * sizeof(wchar_t));
|
||||
if (aLpofn->lpstrFileTitle != nullptr) {
|
||||
MOZ_ASSERT(mFileTitle.size() + 1 < aLpofn->nMaxFileTitle);
|
||||
wcscpy(aLpofn->lpstrFileTitle, mFileTitle.c_str());
|
||||
}
|
||||
aLpofn->nFileOffset = mFileOffset;
|
||||
aLpofn->nFileExtension = mFileExtension;
|
||||
}
|
||||
#endif // XP_WIN
|
||||
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@
|
|||
namespace mac_plugin_interposing { class NSCursorInfo { }; }
|
||||
#endif
|
||||
using mac_plugin_interposing::NSCursorInfo;
|
||||
#ifdef XP_WIN
|
||||
#include "commdlg.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
|
|
@ -123,9 +126,59 @@ typedef intptr_t NativeWindowHandle; // never actually used, will always be 0
|
|||
#ifdef XP_WIN
|
||||
typedef base::SharedMemoryHandle WindowsSharedMemoryHandle;
|
||||
typedef HANDLE DXGISharedSurfaceHandle;
|
||||
#else
|
||||
|
||||
// Values indicate GetOpenFileNameW and GetSaveFileNameW.
|
||||
enum GetFileNameFunc { OPEN_FUNC, SAVE_FUNC };
|
||||
|
||||
// IPC-capable version of the Windows OPENFILENAMEW struct.
|
||||
typedef struct _OpenFileNameIPC
|
||||
{
|
||||
// Allocates memory for the strings in this object. This should usually
|
||||
// be used with a zeroed out OPENFILENAMEW structure.
|
||||
void AllocateOfnStrings(LPOPENFILENAMEW aLpofn) const;
|
||||
void FreeOfnStrings(LPOPENFILENAMEW aLpofn) const;
|
||||
void AddToOfn(LPOPENFILENAMEW aLpofn) const;
|
||||
void CopyFromOfn(LPOPENFILENAMEW aLpofn);
|
||||
|
||||
NativeWindowHandle mHwndOwner;
|
||||
std::wstring mFilter; // Double-NULL terminated (i.e. L"\0\0") if mHasFilter is true
|
||||
bool mHasFilter;
|
||||
std::wstring mCustomFilterIn;
|
||||
bool mHasCustomFilter;
|
||||
uint32_t mNMaxCustFilterOut;
|
||||
uint32_t mFilterIndex;
|
||||
std::wstring mFile;
|
||||
uint32_t mNMaxFile;
|
||||
uint32_t mNMaxFileTitle;
|
||||
std::wstring mInitialDir;
|
||||
bool mHasInitialDir;
|
||||
std::wstring mTitle;
|
||||
bool mHasTitle;
|
||||
uint32_t mFlags;
|
||||
std::wstring mDefExt;
|
||||
bool mHasDefExt;
|
||||
uint32_t mFlagsEx;
|
||||
} OpenFileNameIPC;
|
||||
|
||||
// GetOpenFileNameW and GetSaveFileNameW overwrite fields of their OPENFILENAMEW
|
||||
// parameter. This represents those values so that they can be returned via IPC.
|
||||
typedef struct _OpenFileNameRetIPC
|
||||
{
|
||||
void CopyFromOfn(LPOPENFILENAMEW aLpofn);
|
||||
void AddToOfn(LPOPENFILENAMEW aLpofn) const;
|
||||
|
||||
std::wstring mCustomFilterOut;
|
||||
std::wstring mFile; // Double-NULL terminated (i.e. L"\0\0")
|
||||
std::wstring mFileTitle;
|
||||
uint16_t mFileOffset;
|
||||
uint16_t mFileExtension;
|
||||
} OpenFileNameRetIPC;
|
||||
#else // XP_WIN
|
||||
typedef mozilla::null_t WindowsSharedMemoryHandle;
|
||||
typedef mozilla::null_t DXGISharedSurfaceHandle;
|
||||
typedef mozilla::null_t GetFileNameFunc;
|
||||
typedef mozilla::null_t OpenFileNameIPC;
|
||||
typedef mozilla::null_t OpenFileNameRetIPC;
|
||||
#endif
|
||||
|
||||
// XXX maybe not the best place for these. better one?
|
||||
|
|
@ -723,6 +776,129 @@ struct ParamTraits<mozilla::plugins::NPAudioDeviceChangeDetailsIPC>
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef XP_WIN
|
||||
template <>
|
||||
struct ParamTraits<mozilla::plugins::_OpenFileNameIPC>
|
||||
{
|
||||
typedef mozilla::plugins::_OpenFileNameIPC paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mHwndOwner);
|
||||
WriteParam(aMsg, aParam.mFilter);
|
||||
WriteParam(aMsg, aParam.mHasFilter);
|
||||
WriteParam(aMsg, aParam.mCustomFilterIn);
|
||||
WriteParam(aMsg, aParam.mHasCustomFilter);
|
||||
WriteParam(aMsg, aParam.mNMaxCustFilterOut);
|
||||
WriteParam(aMsg, aParam.mFilterIndex);
|
||||
WriteParam(aMsg, aParam.mFile);
|
||||
WriteParam(aMsg, aParam.mNMaxFile);
|
||||
WriteParam(aMsg, aParam.mNMaxFileTitle);
|
||||
WriteParam(aMsg, aParam.mInitialDir);
|
||||
WriteParam(aMsg, aParam.mHasInitialDir);
|
||||
WriteParam(aMsg, aParam.mTitle);
|
||||
WriteParam(aMsg, aParam.mHasTitle);
|
||||
WriteParam(aMsg, aParam.mFlags);
|
||||
WriteParam(aMsg, aParam.mDefExt);
|
||||
WriteParam(aMsg, aParam.mHasDefExt);
|
||||
WriteParam(aMsg, aParam.mFlagsEx);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
if (ReadParam(aMsg, aIter, &aResult->mHwndOwner) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFilter) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasFilter) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mCustomFilterIn) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasCustomFilter) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mNMaxCustFilterOut) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFilterIndex) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFile) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mNMaxFile) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mNMaxFileTitle) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mInitialDir) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasInitialDir) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mTitle) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasTitle) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFlags) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mDefExt) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasDefExt) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFlagsEx)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%S, %S, %S, %S]", aParam.mFilter.c_str(),
|
||||
aParam.mCustomFilterIn.c_str(), aParam.mFile.c_str(),
|
||||
aParam.mTitle.c_str()));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::plugins::_OpenFileNameRetIPC>
|
||||
{
|
||||
typedef mozilla::plugins::_OpenFileNameRetIPC paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mCustomFilterOut);
|
||||
WriteParam(aMsg, aParam.mFile);
|
||||
WriteParam(aMsg, aParam.mFileTitle);
|
||||
WriteParam(aMsg, aParam.mFileOffset);
|
||||
WriteParam(aMsg, aParam.mFileExtension);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
if (ReadParam(aMsg, aIter, &aResult->mCustomFilterOut) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFile) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFileTitle) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFileOffset) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFileExtension)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%S, %S, %S, %d, %d]", aParam.mCustomFilterOut.c_str(),
|
||||
aParam.mFile.c_str(), aParam.mFileTitle.c_str(),
|
||||
aParam.mFileOffset, aParam.mFileExtension));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::plugins::GetFileNameFunc>
|
||||
{
|
||||
typedef mozilla::plugins::GetFileNameFunc paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, static_cast<uint32_t>(aParam));
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
uint32_t result;
|
||||
if (ReadParam(aMsg, aIter, &result)) {
|
||||
*aResult = static_cast<paramType>(result);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%S]",
|
||||
aParam == mozilla::plugins::OPEN_FUNC ? "GetOpenFileName" : "GetSaveFileName"));
|
||||
}
|
||||
};
|
||||
#endif // XP_WIN
|
||||
|
||||
} /* namespace IPC */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,17 @@ static HWND sBrowserHwnd = nullptr;
|
|||
// sandbox process doesn't get current key states. So we need get it on chrome.
|
||||
typedef SHORT (WINAPI *GetKeyStatePtr)(int);
|
||||
static GetKeyStatePtr sGetKeyStatePtrStub = nullptr;
|
||||
|
||||
static WindowsDllInterceptor sComDlg32Intercept;
|
||||
|
||||
// proxy GetSaveFileName/GetOpenFileName on chrome so that we can know which
|
||||
// files the user has given permission to access
|
||||
// We count on GetOpenFileNameA/GetSaveFileNameA calling
|
||||
// GetOpenFileNameW/GetSaveFileNameW so we don't proxy them explicitly.
|
||||
typedef BOOL (WINAPI *GetOpenFileNameWPtr)(LPOPENFILENAMEW lpofn);
|
||||
static GetOpenFileNameWPtr sGetOpenFileNameWPtrStub = nullptr;
|
||||
typedef BOOL (WINAPI *GetSaveFileNameWPtr)(LPOPENFILENAMEW lpofn);
|
||||
static GetSaveFileNameWPtr sGetSaveFileNameWPtrStub = nullptr;
|
||||
#endif
|
||||
|
||||
/* static */
|
||||
|
|
@ -2111,6 +2122,124 @@ PMCGetKeyState(int aVirtKey)
|
|||
}
|
||||
return sGetKeyStatePtrStub(aVirtKey);
|
||||
}
|
||||
|
||||
BOOL WINAPI PMCGetSaveFileNameW(LPOPENFILENAMEW lpofn);
|
||||
BOOL WINAPI PMCGetOpenFileNameW(LPOPENFILENAMEW lpofn);
|
||||
|
||||
// Runnable that performs GetOpenFileNameW and GetSaveFileNameW
|
||||
// on the main thread so that the call can be
|
||||
// synchronously run on the PluginModuleParent via IPC.
|
||||
// The task alerts the given semaphore when it is finished.
|
||||
class GetFileNameTask : public Runnable
|
||||
{
|
||||
BOOL* mReturnValue;
|
||||
void* mLpOpenFileName;
|
||||
HANDLE mSemaphore;
|
||||
GetFileNameFunc mFunc;
|
||||
|
||||
public:
|
||||
explicit GetFileNameTask(GetFileNameFunc func, void* aLpOpenFileName,
|
||||
HANDLE aSemaphore, BOOL* aReturnValue) :
|
||||
mLpOpenFileName(aLpOpenFileName), mSemaphore(aSemaphore),
|
||||
mReturnValue(aReturnValue), mFunc(func)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_METHOD;
|
||||
AssertPluginThread();
|
||||
switch (mFunc) {
|
||||
case OPEN_FUNC:
|
||||
*mReturnValue =
|
||||
PMCGetOpenFileNameW(static_cast<LPOPENFILENAMEW>(mLpOpenFileName));
|
||||
break;
|
||||
case SAVE_FUNC:
|
||||
*mReturnValue =
|
||||
PMCGetSaveFileNameW(static_cast<LPOPENFILENAMEW>(mLpOpenFileName));
|
||||
break;
|
||||
}
|
||||
if (!ReleaseSemaphore(mSemaphore, 1, nullptr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
// static
|
||||
BOOL
|
||||
PostToPluginThread(GetFileNameFunc aFunc, void* aLpofn)
|
||||
{
|
||||
MOZ_ASSERT(!IsPluginThread());
|
||||
|
||||
// Synchronously run GetFileNameTask from the main thread.
|
||||
// Start a semaphore at 0. We release the semaphore (bringing its
|
||||
// count to 1) when the synchronous call is done.
|
||||
nsAutoHandle semaphore(CreateSemaphore(NULL, 0, 1, NULL));
|
||||
if (semaphore == nullptr) {
|
||||
MOZ_ASSERT(semaphore != nullptr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL returnValue = FALSE;
|
||||
RefPtr<GetFileNameTask> task =
|
||||
new GetFileNameTask(aFunc, aLpofn, semaphore, &returnValue);
|
||||
ProcessChild::message_loop()->PostTask(task.forget());
|
||||
DWORD err = WaitForSingleObject(semaphore, INFINITE);
|
||||
if (err != WAIT_FAILED) {
|
||||
return returnValue;
|
||||
}
|
||||
PLUGIN_LOG_DEBUG(("Error while waiting for semaphore: %d",
|
||||
GetLastError()));
|
||||
MOZ_ASSERT(err != WAIT_FAILED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL WINAPI
|
||||
PMCGetFileNameW(GetFileNameFunc aFunc, LPOPENFILENAMEW aLpofn)
|
||||
{
|
||||
if (!IsPluginThread()) {
|
||||
return PostToPluginThread(aFunc, aLpofn);
|
||||
}
|
||||
|
||||
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
|
||||
if (chromeInstance) {
|
||||
bool ret = FALSE;
|
||||
OpenFileNameIPC inputOfn;
|
||||
inputOfn.CopyFromOfn(aLpofn);
|
||||
OpenFileNameRetIPC outputOfn;
|
||||
if (chromeInstance->CallGetFileName(aFunc, inputOfn,
|
||||
&outputOfn, &ret)) {
|
||||
if (ret) {
|
||||
outputOfn.AddToOfn(aLpofn);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (aFunc) {
|
||||
case OPEN_FUNC:
|
||||
return sGetOpenFileNameWPtrStub(aLpofn);
|
||||
case SAVE_FUNC:
|
||||
return sGetSaveFileNameWPtrStub(aLpofn);
|
||||
}
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("Illegal GetFileNameFunc value");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL WINAPI
|
||||
PMCGetSaveFileNameW(LPOPENFILENAMEW aLpofn)
|
||||
{
|
||||
return PMCGetFileNameW(SAVE_FUNC, aLpofn);
|
||||
}
|
||||
// static
|
||||
BOOL WINAPI
|
||||
PMCGetOpenFileNameW(LPOPENFILENAMEW aLpofn)
|
||||
{
|
||||
return PMCGetFileNameW(OPEN_FUNC, aLpofn);
|
||||
}
|
||||
#endif
|
||||
|
||||
PPluginInstanceChild*
|
||||
|
|
@ -2143,6 +2272,17 @@ PluginModuleChild::AllocPPluginInstanceChild(const nsCString& aMimeType,
|
|||
sUser32Intercept.AddHook("GetKeyState", reinterpret_cast<intptr_t>(PMCGetKeyState),
|
||||
(void**) &sGetKeyStatePtrStub);
|
||||
}
|
||||
|
||||
sComDlg32Intercept.Init("comdlg32.dll");
|
||||
if (!sGetSaveFileNameWPtrStub) {
|
||||
sComDlg32Intercept.AddHook("GetSaveFileNameW", reinterpret_cast<intptr_t>(PMCGetSaveFileNameW),
|
||||
(void**) &sGetSaveFileNameWPtrStub);
|
||||
}
|
||||
|
||||
if (!sGetOpenFileNameWPtrStub) {
|
||||
sComDlg32Intercept.AddHook("GetOpenFileNameW", reinterpret_cast<intptr_t>(PMCGetOpenFileNameW),
|
||||
(void**) &sGetOpenFileNameWPtrStub);
|
||||
}
|
||||
#endif
|
||||
|
||||
return new PluginInstanceChild(&mFunctions, aMimeType, aMode, aNames,
|
||||
|
|
|
|||
|
|
@ -18,9 +18,6 @@
|
|||
#include "mozilla/plugins/PluginBridge.h"
|
||||
#include "mozilla/plugins/PluginInstanceParent.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
#include "mozilla/ProfileGatherer.h"
|
||||
#endif
|
||||
#include "mozilla/ProcessHangMonitor.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
|
@ -61,9 +58,6 @@
|
|||
using base::KillProcess;
|
||||
|
||||
using mozilla::PluginLibrary;
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
using mozilla::ProfileGatherer;
|
||||
#endif
|
||||
using mozilla::ipc::MessageChannel;
|
||||
using mozilla::ipc::GeckoChildProcessHost;
|
||||
|
||||
|
|
@ -649,10 +643,7 @@ PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded)
|
|||
rv = profiler->GetStartParams(getter_AddRefs(currentProfilerParams));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
nsCOMPtr<nsISupports> gatherer;
|
||||
rv = profiler->GetProfileGatherer(getter_AddRefs(gatherer));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
mGatherer = static_cast<ProfileGatherer*>(gatherer.get());
|
||||
mIsProfilerActive = true;
|
||||
|
||||
StartProfiler(currentProfilerParams);
|
||||
}
|
||||
|
|
@ -781,6 +772,9 @@ PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath,
|
|||
, mAsyncInitRv(NS_ERROR_NOT_INITIALIZED)
|
||||
, mAsyncInitError(NPERR_NO_ERROR)
|
||||
, mContentParent(nullptr)
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
, mIsProfilerActive(false)
|
||||
#endif
|
||||
{
|
||||
NS_ASSERTION(mSubprocess, "Out of memory!");
|
||||
sInstantiated = true;
|
||||
|
|
@ -810,6 +804,10 @@ PluginModuleChromeParent::~PluginModuleChromeParent()
|
|||
false);
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
mSandboxPermissions.RemovePermissionsForProcess(OtherPid());
|
||||
#endif
|
||||
|
||||
if (!mShutdown) {
|
||||
NS_WARNING("Plugin host deleted the module without shutting down.");
|
||||
NPError err;
|
||||
|
|
@ -3370,25 +3368,23 @@ PluginModuleChromeParent::StartProfiler(nsIProfilerStartParams* aParams)
|
|||
if (NS_WARN_IF(!profiler)) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsISupports> gatherer;
|
||||
profiler->GetProfileGatherer(getter_AddRefs(gatherer));
|
||||
mGatherer = static_cast<ProfileGatherer*>(gatherer.get());
|
||||
mIsProfilerActive = true;
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::StopProfiler()
|
||||
{
|
||||
mGatherer = nullptr;
|
||||
mIsProfilerActive = false;
|
||||
Unused << SendStopProfiler();
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::GatherAsyncProfile()
|
||||
{
|
||||
if (NS_WARN_IF(!mGatherer)) {
|
||||
if (NS_WARN_IF(!mIsProfilerActive)) {
|
||||
return;
|
||||
}
|
||||
mGatherer->WillGatherOOPProfile();
|
||||
profiler_will_gather_OOP_profile();
|
||||
Unused << SendGatherProfile();
|
||||
}
|
||||
|
||||
|
|
@ -3406,12 +3402,12 @@ mozilla::ipc::IPCResult
|
|||
PluginModuleChromeParent::RecvProfile(const nsCString& aProfile)
|
||||
{
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
if (NS_WARN_IF(!mGatherer)) {
|
||||
if (NS_WARN_IF(!mIsProfilerActive)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mProfile = aProfile;
|
||||
mGatherer->GatheredOOPProfile();
|
||||
profiler_gathered_OOP_profile();
|
||||
#endif
|
||||
return IPC_OK();
|
||||
}
|
||||
|
|
@ -3433,3 +3429,69 @@ PluginModuleChromeParent::AnswerGetKeyState(const int32_t& aVirtKey,
|
|||
return PluginModuleParent::AnswerGetKeyState(aVirtKey, aRet);
|
||||
#endif
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
PluginModuleChromeParent::AnswerGetFileName(const GetFileNameFunc& aFunc,
|
||||
const OpenFileNameIPC& aOfnIn,
|
||||
OpenFileNameRetIPC* aOfnOut,
|
||||
bool* aResult)
|
||||
{
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
OPENFILENAMEW ofn;
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
aOfnIn.AllocateOfnStrings(&ofn);
|
||||
aOfnIn.AddToOfn(&ofn);
|
||||
switch (aFunc) {
|
||||
case OPEN_FUNC:
|
||||
*aResult = GetOpenFileName(&ofn);
|
||||
break;
|
||||
case SAVE_FUNC:
|
||||
*aResult = GetSaveFileName(&ofn);
|
||||
break;
|
||||
}
|
||||
if (*aResult) {
|
||||
if (ofn.Flags & OFN_ALLOWMULTISELECT) {
|
||||
// We only support multiselect with the OFN_EXPLORER flag.
|
||||
// This guarantees that ofn.lpstrFile follows the pattern below.
|
||||
MOZ_ASSERT(ofn.Flags & OFN_EXPLORER);
|
||||
|
||||
// lpstrFile is one of two things:
|
||||
// 1. A null terminated full path to a file, or
|
||||
// 2. A path to a folder, followed by a NULL, followed by a
|
||||
// list of file names, each NULL terminated, followed by an
|
||||
// additional NULL (so it is also double-NULL terminated).
|
||||
std::wstring path = std::wstring(ofn.lpstrFile);
|
||||
MOZ_ASSERT(ofn.nFileOffset > 0);
|
||||
// For condition #1, nFileOffset points to the file name in the path.
|
||||
// It will be preceeded by a non-NULL character from the path.
|
||||
if (ofn.lpstrFile[ofn.nFileOffset-1] != L'\0') {
|
||||
mSandboxPermissions.GrantFileAccess(OtherPid(), path.c_str(),
|
||||
aFunc == SAVE_FUNC);
|
||||
}
|
||||
else {
|
||||
// This is condition #2
|
||||
wchar_t* nextFile = ofn.lpstrFile + path.size() + 1;
|
||||
while (*nextFile != L'\0') {
|
||||
std::wstring nextFileStr(nextFile);
|
||||
std::wstring fullPath =
|
||||
path + std::wstring(L"\\") + nextFileStr;
|
||||
mSandboxPermissions.GrantFileAccess(OtherPid(), fullPath.c_str(),
|
||||
aFunc == SAVE_FUNC);
|
||||
nextFile += nextFileStr.size() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mSandboxPermissions.GrantFileAccess(OtherPid(), ofn.lpstrFile,
|
||||
aFunc == SAVE_FUNC);
|
||||
}
|
||||
aOfnOut->CopyFromOfn(&ofn);
|
||||
}
|
||||
aOfnIn.FreeOfnStrings(&ofn);
|
||||
return IPC_OK();
|
||||
#else
|
||||
MOZ_ASSERT_UNREACHABLE("GetFileName IPC message is only available on "
|
||||
"Windows builds with sandbox.");
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "nsIObserver.h"
|
||||
#ifdef XP_WIN
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "sandboxPermissions.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
|
|
@ -34,9 +35,6 @@ class nsIProfileSaveEvent;
|
|||
class nsPluginTag;
|
||||
|
||||
namespace mozilla {
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
class ProfileGatherer;
|
||||
#endif
|
||||
|
||||
namespace ipc {
|
||||
class CrashReporterHost;
|
||||
|
|
@ -194,6 +192,14 @@ protected:
|
|||
const bool& shouldRegister,
|
||||
NPError* result) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
AnswerGetFileName(const GetFileNameFunc& aFunc,
|
||||
const OpenFileNameIPC& aOfnIn,
|
||||
OpenFileNameRetIPC* aOfnOut, bool* aResult) override
|
||||
{
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetChildTimeout(const int32_t aChildTimeout);
|
||||
static void TimeoutChanged(const char* aPref, void* aModule);
|
||||
|
|
@ -509,6 +515,12 @@ class PluginModuleChromeParent
|
|||
virtual mozilla::ipc::IPCResult
|
||||
AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
|
||||
|
||||
// Proxy GetOpenFileName/GetSaveFileName on Windows.
|
||||
virtual mozilla::ipc::IPCResult
|
||||
AnswerGetFileName(const GetFileNameFunc& aFunc,
|
||||
const OpenFileNameIPC& aOfnIn,
|
||||
OpenFileNameRetIPC* aOfnOut, bool* aResult) override;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
EnteredCxxStack() override;
|
||||
|
|
@ -657,11 +669,14 @@ private:
|
|||
dom::ContentParent* mContentParent;
|
||||
nsCOMPtr<nsIObserver> mPluginOfflineObserver;
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
RefPtr<mozilla::ProfileGatherer> mGatherer;
|
||||
bool mIsProfilerActive;
|
||||
#endif
|
||||
nsCString mProfile;
|
||||
bool mIsBlocklisted;
|
||||
static bool sInstantiated;
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
mozilla::SandboxPermissions mSandboxPermissions;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
|
|
|
|||
|
|
@ -97,13 +97,6 @@ AddSandboxAllowedFiles(int32_t aSandboxLevel,
|
|||
return;
|
||||
}
|
||||
|
||||
// Higher than level 2 currently removes the users own rights.
|
||||
if (aSandboxLevel > 2) {
|
||||
AddSandboxAllowedFile(aAllowedFilesRead, dirSvc, NS_WIN_HOME_DIR);
|
||||
AddSandboxAllowedFile(aAllowedFilesRead, dirSvc, NS_WIN_HOME_DIR,
|
||||
NS_LITERAL_STRING("\\*"));
|
||||
}
|
||||
|
||||
// Level 2 and above is now using low integrity, so we need to give write
|
||||
// access to the Flash directories.
|
||||
// This should be made Flash specific (Bug 1171396).
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
|
|||
LOCAL_INCLUDES += [
|
||||
'/security/sandbox/chromium',
|
||||
'/security/sandbox/chromium-shim',
|
||||
'/security/sandbox/win/src/sandboxpermissions',
|
||||
]
|
||||
|
||||
DEFINES['FORCE_PR_LOG'] = True
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ subsuite = clipboard
|
|||
subsuite = clipboard
|
||||
[test_consoleAPI.html]
|
||||
[test_contentViewer_overrideDPPX.html]
|
||||
[test_CCW_optimization.html]
|
||||
[test_DOMMatrix.html]
|
||||
[test_domWindowUtils.html]
|
||||
[test_domWindowUtils_scrollbarSize.html]
|
||||
|
|
|
|||
50
dom/tests/mochitest/general/test_CCW_optimization.html
Normal file
50
dom/tests/mochitest/general/test_CCW_optimization.html
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1319087
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1319087</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1319087">Mozilla Bug 1319087</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<iframe></iframe>
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
|
||||
function WrapperToOwnCompartment() {
|
||||
var iframe = new frames[0].Object();
|
||||
var obj = iframe.obj = new Object();
|
||||
obj.x = 123;
|
||||
|
||||
for (var i = 0; i < 50; i++) {
|
||||
is(iframe.obj, obj);
|
||||
is(iframe.obj.x, 123);
|
||||
}
|
||||
}
|
||||
|
||||
function WrapperToYetAnotherCompartment() {
|
||||
var iframe = new frames[0].Object();
|
||||
// Obj points to an object in a third compartment.
|
||||
var obj = iframe.obj = new frames[1].Object();
|
||||
obj.x = 42;
|
||||
|
||||
for (var i = 0; i < 50; i++) {
|
||||
is(iframe.obj, obj);
|
||||
is(iframe.obj.x, 42);
|
||||
}
|
||||
}
|
||||
|
||||
WrapperToOwnCompartment();
|
||||
WrapperToYetAnotherCompartment();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -38,7 +38,11 @@ partial interface File {
|
|||
|
||||
[GetterThrows, ChromeOnly, NeedsCallerType]
|
||||
readonly attribute DOMString mozFullPath;
|
||||
};
|
||||
|
||||
// Mozilla extensions - main-thread only
|
||||
[Exposed=(Window)]
|
||||
partial interface File {
|
||||
[ChromeOnly, Throws, NeedsCallerType]
|
||||
static Promise<File> createFromNsIFile(nsIFile file,
|
||||
optional ChromeFilePropertyBag options);
|
||||
|
|
|
|||
|
|
@ -1243,6 +1243,44 @@ CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(
|
|||
return isSet;
|
||||
}
|
||||
|
||||
bool
|
||||
CSSEditUtils::HaveCSSEquivalentStyles(
|
||||
nsINode& aNode,
|
||||
nsIAtom* aHTMLProperty,
|
||||
nsIAtom* aHTMLAttribute,
|
||||
StyleType aStyleType)
|
||||
{
|
||||
nsAutoString valueString;
|
||||
nsCOMPtr<nsINode> node = &aNode;
|
||||
do {
|
||||
// get the value of the CSS equivalent styles
|
||||
nsresult rv =
|
||||
GetCSSEquivalentToHTMLInlineStyleSet(node, aHTMLProperty, aHTMLAttribute,
|
||||
valueString, aStyleType);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!valueString.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nsGkAtoms::u != aHTMLProperty && nsGkAtoms::strike != aHTMLProperty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// unfortunately, the value of the text-decoration property is not
|
||||
// inherited.
|
||||
// that means that we have to look at ancestors of node to see if they
|
||||
// are underlined
|
||||
|
||||
// set to null if it's not a dom element
|
||||
node = node->GetParentElement();
|
||||
} while (node);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CSSEditUtils::SetCSSEnabled(bool aIsCSSPrefChecked)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ public:
|
|||
* values (out).
|
||||
* @param aStyleType [IN] eSpecified or eComputed.
|
||||
* @return A boolean being true if the css properties are
|
||||
* set.
|
||||
* not same as initial value.
|
||||
*/
|
||||
bool IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aContent,
|
||||
nsIAtom* aProperty,
|
||||
|
|
@ -239,6 +239,29 @@ public:
|
|||
nsAString& aValue,
|
||||
StyleType aStyleType);
|
||||
|
||||
/**
|
||||
* This is a kind of IsCSSEquivalentToHTMLInlineStyleSet.
|
||||
* IsCSSEquivalentToHTMLInlineStyleSet returns whether the properties
|
||||
* aren't same as initial value. But this method returns whether the
|
||||
* properties aren't set.
|
||||
* If node is <span style="font-weight: normal"/>,
|
||||
* - IsCSSEquivalentToHTMLInlineStyleSet returns false.
|
||||
* - HaveCSSEquivalentStyles returns true.
|
||||
*
|
||||
* @param aNode [IN] A DOM node.
|
||||
* @param aHTMLProperty [IN] An atom containing an HTML property.
|
||||
* @param aAttribute [IN] An atom to an attribute name or nullptr
|
||||
* if irrelevant.
|
||||
* @param aStyleType [IN] eSpecified or eComputed.
|
||||
* @return A boolean being true if the css properties are
|
||||
* not set.
|
||||
*/
|
||||
|
||||
bool HaveCSSEquivalentStyles(nsINode& aNode,
|
||||
nsIAtom* aProperty,
|
||||
nsIAtom* aAttribute,
|
||||
StyleType aStyleType);
|
||||
|
||||
/**
|
||||
* Adds to the node the CSS inline styles equivalent to the HTML style
|
||||
* and return the number of CSS properties set by the call.
|
||||
|
|
|
|||
|
|
@ -778,22 +778,25 @@ HTMLEditor::RemoveStyleInside(nsIContent& aNode,
|
|||
// the HTML style defined by aProperty/aAttribute has a CSS equivalence in
|
||||
// this implementation for the node aNode; let's check if it carries those
|
||||
// css styles
|
||||
nsCOMPtr<nsIAtom> attribute =
|
||||
aAttribute ? NS_Atomize(*aAttribute) : nullptr;
|
||||
nsAutoString propertyValue;
|
||||
bool isSet = mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(&aNode,
|
||||
aProperty, attribute, propertyValue, CSSEditUtils::eSpecified);
|
||||
if (isSet && aNode.IsElement()) {
|
||||
// yes, tmp has the corresponding css declarations in its style attribute
|
||||
// let's remove them
|
||||
mCSSEditUtils->RemoveCSSEquivalentToHTMLStyle(aNode.AsElement(),
|
||||
aProperty,
|
||||
attribute,
|
||||
&propertyValue,
|
||||
false);
|
||||
// remove the node if it is a span or font, if its style attribute is
|
||||
// empty or absent, and if it does not have a class nor an id
|
||||
RemoveElementIfNoStyleOrIdOrClass(*aNode.AsElement());
|
||||
if (aNode.IsElement()) {
|
||||
nsCOMPtr<nsIAtom> attribute =
|
||||
aAttribute ? NS_Atomize(*aAttribute) : nullptr;
|
||||
bool hasAttribute =
|
||||
mCSSEditUtils->HaveCSSEquivalentStyles(
|
||||
aNode, aProperty, attribute, CSSEditUtils::eSpecified);
|
||||
if (hasAttribute) {
|
||||
// yes, tmp has the corresponding css declarations in its style
|
||||
// attribute
|
||||
// let's remove them
|
||||
mCSSEditUtils->RemoveCSSEquivalentToHTMLStyle(aNode.AsElement(),
|
||||
aProperty,
|
||||
attribute,
|
||||
nullptr,
|
||||
false);
|
||||
// remove the node if it is a span or font, if its style attribute is
|
||||
// empty or absent, and if it does not have a class nor an id
|
||||
RemoveElementIfNoStyleOrIdOrClass(*aNode.AsElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,64 +0,0 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#include "TiledLayerBuffer.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
TEST(TiledLayerBuffer, TileStart) {
|
||||
ASSERT_EQ(RoundDownToTileEdge(10, 256), 0);
|
||||
ASSERT_EQ(RoundDownToTileEdge(-10, 256), -256);
|
||||
}
|
||||
|
||||
TEST(TiledLayerBuffer, TilesPlacement) {
|
||||
for (int firstY = -10; firstY < 10; ++firstY) {
|
||||
for (int firstX = -10; firstX < 10; ++firstX) {
|
||||
for (int height = 1; height < 10; ++height) {
|
||||
for (int width = 1; width < 10; ++width) {
|
||||
|
||||
const TilesPlacement p1 = TilesPlacement(firstX, firstY, width, height);
|
||||
// Check that HasTile returns false with some positions that we know
|
||||
// not to be in the rectangle of the TilesPlacement.
|
||||
ASSERT_FALSE(p1.HasTile(TileIntPoint(firstX - 1, 0)));
|
||||
ASSERT_FALSE(p1.HasTile(TileIntPoint(0, firstY - 1)));
|
||||
ASSERT_FALSE(p1.HasTile(TileIntPoint(firstX + width + 1, 0)));
|
||||
ASSERT_FALSE(p1.HasTile(TileIntPoint(0, firstY + height + 1)));
|
||||
|
||||
// Verify that all positions within the rect that defines the
|
||||
// TilesPlacement map to indices between 0 and width*height.
|
||||
for (int y = firstY; y < (firstY+height); ++y) {
|
||||
for (int x = firstX; x < (firstX+width); ++x) {
|
||||
ASSERT_TRUE(p1.HasTile(TileIntPoint(x,y)));
|
||||
ASSERT_TRUE(p1.TileIndex(TileIntPoint(x, y)) >= 0);
|
||||
ASSERT_TRUE(p1.TileIndex(TileIntPoint(x, y)) < width * height);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX - This causes some versions of gcc to warn that it optimizes
|
||||
// away the test, which gets caught in -WError in PGO builds.
|
||||
// The lazy thing to do is to just comment this out since this specific
|
||||
// test isn't critically important, but we should remove the warning instead.
|
||||
// cf. bug 1179287
|
||||
//
|
||||
// Verify that indices map to positions that are within the rect that
|
||||
// defines the TilesPlacement.
|
||||
// for (int i = 0; i < width * height; ++i) {
|
||||
// ASSERT_TRUE(p1.TilePosition(i).x >= firstX);
|
||||
// ASSERT_TRUE(p1.TilePosition(i).x < firstX + width);
|
||||
// ASSERT_TRUE(p1.TilePosition(i).y >= firstY);
|
||||
// ASSERT_TRUE(p1.TilePosition(i).y < firstY + height);
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,320 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "gtest/gtest.h"
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsString.h"
|
||||
#include "nsDependentString.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#include "gfxFontTest.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
enum {
|
||||
S_UTF8 = 0,
|
||||
S_ASCII = 1
|
||||
};
|
||||
|
||||
class FrameTextRunCache;
|
||||
|
||||
struct LiteralArray {
|
||||
LiteralArray (unsigned long l1) {
|
||||
data.AppendElement(l1);
|
||||
}
|
||||
LiteralArray (unsigned long l1, unsigned long l2) {
|
||||
data.AppendElement(l1);
|
||||
data.AppendElement(l2);
|
||||
}
|
||||
LiteralArray (unsigned long l1, unsigned long l2, unsigned long l3) {
|
||||
data.AppendElement(l1);
|
||||
data.AppendElement(l2);
|
||||
data.AppendElement(l3);
|
||||
}
|
||||
LiteralArray (unsigned long l1, unsigned long l2, unsigned long l3, unsigned long l4) {
|
||||
data.AppendElement(l1);
|
||||
data.AppendElement(l2);
|
||||
data.AppendElement(l3);
|
||||
data.AppendElement(l4);
|
||||
}
|
||||
LiteralArray (unsigned long l1, unsigned long l2, unsigned long l3, unsigned long l4, unsigned long l5) {
|
||||
data.AppendElement(l1);
|
||||
data.AppendElement(l2);
|
||||
data.AppendElement(l3);
|
||||
data.AppendElement(l4);
|
||||
data.AppendElement(l5);
|
||||
}
|
||||
|
||||
LiteralArray (const LiteralArray& other) {
|
||||
data = other.data;
|
||||
}
|
||||
|
||||
nsTArray<unsigned long> data;
|
||||
};
|
||||
|
||||
#define GLYPHS LiteralArray
|
||||
|
||||
struct TestEntry {
|
||||
TestEntry (const char *aUTF8FamilyString,
|
||||
const gfxFontStyle& aFontStyle,
|
||||
const char *aString)
|
||||
: utf8FamilyString(aUTF8FamilyString),
|
||||
fontStyle(aFontStyle),
|
||||
stringType(S_ASCII),
|
||||
string(aString),
|
||||
isRTL(false)
|
||||
{
|
||||
}
|
||||
|
||||
TestEntry (const char *aUTF8FamilyString,
|
||||
const gfxFontStyle& aFontStyle,
|
||||
int stringType,
|
||||
const char *aString)
|
||||
: utf8FamilyString(aUTF8FamilyString),
|
||||
fontStyle(aFontStyle),
|
||||
stringType(stringType),
|
||||
string(aString),
|
||||
isRTL(false)
|
||||
{
|
||||
}
|
||||
|
||||
struct ExpectItem {
|
||||
ExpectItem(const nsCString& aFontName,
|
||||
const LiteralArray& aGlyphs)
|
||||
: fontName(aFontName), glyphs(aGlyphs)
|
||||
{ }
|
||||
|
||||
bool Compare(const nsCString& aFontName,
|
||||
cairo_glyph_t *aGlyphs,
|
||||
int num_glyphs)
|
||||
{
|
||||
// bit that allowed for empty fontname to match all is commented
|
||||
// out
|
||||
if (/*!fontName.IsEmpty() &&*/ !fontName.Equals(aFontName))
|
||||
return false;
|
||||
|
||||
if (num_glyphs != int(glyphs.data.Length()))
|
||||
return false;
|
||||
|
||||
for (int j = 0; j < num_glyphs; j++) {
|
||||
if (glyphs.data[j] != aGlyphs[j].index)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCString fontName;
|
||||
LiteralArray glyphs;
|
||||
};
|
||||
|
||||
void SetRTL()
|
||||
{
|
||||
isRTL = true;
|
||||
}
|
||||
|
||||
// Empty/nullptr fontName means ignore font name
|
||||
void Expect (const char *platform,
|
||||
const char *fontName,
|
||||
const LiteralArray& glyphs)
|
||||
{
|
||||
if (fontName)
|
||||
Expect (platform, nsDependentCString(fontName), glyphs);
|
||||
else
|
||||
Expect (platform, nsCString(), glyphs);
|
||||
}
|
||||
|
||||
void Expect (const char *platform,
|
||||
const nsCString& fontName,
|
||||
const LiteralArray& glyphs)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
if (strcmp(platform, "win32"))
|
||||
return;
|
||||
#elif defined(XP_MACOSX)
|
||||
if (strcmp(platform, "macosx"))
|
||||
return;
|
||||
#elif defined(XP_UNIX)
|
||||
if (strcmp(platform, "gtk2-pango"))
|
||||
return;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
||||
expectItems.AppendElement(ExpectItem(fontName, glyphs));
|
||||
}
|
||||
|
||||
bool Check (gfxFontTestStore *store) {
|
||||
if (expectItems.Length() == 0 ||
|
||||
store->items.Length() != expectItems.Length())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < expectItems.Length(); i++) {
|
||||
if (!expectItems[i].Compare(store->items[i].platformFont,
|
||||
store->items[i].glyphs,
|
||||
store->items[i].num_glyphs))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *utf8FamilyString;
|
||||
gfxFontStyle fontStyle;
|
||||
|
||||
int stringType;
|
||||
const char *string;
|
||||
bool isRTL;
|
||||
|
||||
nsTArray<ExpectItem> expectItems;
|
||||
};
|
||||
|
||||
static already_AddRefed<gfxContext>
|
||||
MakeContext ()
|
||||
{
|
||||
const int size = 200;
|
||||
|
||||
RefPtr<DrawTarget> drawTarget = gfxPlatform::GetPlatform()->
|
||||
CreateOffscreenContentDrawTarget(IntSize(size, size),
|
||||
SurfaceFormat::B8G8R8X8);
|
||||
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(drawTarget);
|
||||
if (!ctx) {
|
||||
MOZ_CRASH("gfxContext creation failed");
|
||||
}
|
||||
|
||||
return ctx.forget();
|
||||
}
|
||||
|
||||
TestEntry*
|
||||
AddTest (nsTArray<TestEntry>& testList,
|
||||
const char *utf8FamilyString,
|
||||
const gfxFontStyle& fontStyle,
|
||||
int stringType,
|
||||
const char *string)
|
||||
{
|
||||
TestEntry te (utf8FamilyString,
|
||||
fontStyle,
|
||||
stringType,
|
||||
string);
|
||||
|
||||
testList.AppendElement(te);
|
||||
|
||||
return &(testList[testList.Length()-1]);
|
||||
}
|
||||
|
||||
void
|
||||
DumpStore (gfxFontTestStore *store) {
|
||||
if (store->items.Length() == 0) {
|
||||
printf ("(empty)\n");
|
||||
}
|
||||
|
||||
for (uint32_t i = 0;
|
||||
i < store->items.Length();
|
||||
i++)
|
||||
{
|
||||
printf ("Run[% 2d]: '%s' ", i, store->items[i].platformFont.BeginReading());
|
||||
|
||||
for (int j = 0; j < store->items[i].num_glyphs; j++)
|
||||
printf ("%d ", int(store->items[i].glyphs[j].index));
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DumpTestExpect (TestEntry *test) {
|
||||
for (uint32_t i = 0; i < test->expectItems.Length(); i++) {
|
||||
printf ("Run[% 2d]: '%s' ", i, test->expectItems[i].fontName.BeginReading());
|
||||
for (uint32_t j = 0; j < test->expectItems[i].glyphs.data.Length(); j++)
|
||||
printf ("%d ", int(test->expectItems[i].glyphs.data[j]));
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void SetupTests(nsTArray<TestEntry>& testList);
|
||||
|
||||
static bool
|
||||
RunTest (TestEntry *test, gfxContext *ctx) {
|
||||
RefPtr<gfxFontGroup> fontGroup;
|
||||
|
||||
fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->utf8FamilyString), &test->fontStyle, nullptr, nullptr, 1.0);
|
||||
|
||||
RefPtr<gfxTextRun> textRun;
|
||||
gfxTextRunFactory::Parameters params = {
|
||||
ctx, nullptr, nullptr, nullptr, 0, 60
|
||||
};
|
||||
uint32_t flags = gfxTextRunFactory::TEXT_IS_PERSISTENT;
|
||||
if (test->isRTL) {
|
||||
flags |= gfxTextRunFactory::TEXT_IS_RTL;
|
||||
}
|
||||
uint32_t length;
|
||||
if (test->stringType == S_ASCII) {
|
||||
flags |= gfxTextRunFactory::TEXT_IS_ASCII | gfxTextRunFactory::TEXT_IS_8BIT;
|
||||
length = strlen(test->string);
|
||||
textRun = fontGroup->MakeTextRun(
|
||||
reinterpret_cast<const uint8_t*>(test->string), length, ¶ms, flags);
|
||||
} else {
|
||||
NS_ConvertUTF8toUTF16 str(nsDependentCString(test->string));
|
||||
length = str.Length();
|
||||
textRun = fontGroup->MakeTextRun(str.get(), length, ¶ms, flags);
|
||||
}
|
||||
|
||||
gfxFontTestStore::NewStore();
|
||||
textRun->Draw(ctx, gfxPoint(0,0), DrawMode::GLYPH_FILL, 0, length, nullptr, nullptr, nullptr);
|
||||
gfxFontTestStore *s = gfxFontTestStore::CurrentStore();
|
||||
|
||||
if (!test->Check(s)) {
|
||||
DumpStore(s);
|
||||
printf (" expected:\n");
|
||||
DumpTestExpect(test);
|
||||
gfxFontTestStore::DeleteStore();
|
||||
return false;
|
||||
}
|
||||
|
||||
gfxFontTestStore::DeleteStore();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(Gfx, FontSelection) {
|
||||
int passed = 0;
|
||||
int failed = 0;
|
||||
|
||||
// set up the tests
|
||||
nsTArray<TestEntry> testList;
|
||||
SetupTests(testList);
|
||||
|
||||
RefPtr<gfxContext> context = MakeContext();
|
||||
|
||||
for (uint32_t test = 0;
|
||||
test < testList.Length();
|
||||
test++)
|
||||
{
|
||||
bool result = RunTest (&testList[test], context);
|
||||
if (result) {
|
||||
passed++;
|
||||
} else {
|
||||
printf ("Test %d failed\n", test);
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The tests themselves
|
||||
|
||||
#include "gfxFontSelectionTests.h"
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
/*
|
||||
*
|
||||
* This file is #included directly by gfxFontSelectionTest.cpp, and as
|
||||
* such does not need any #include files or similar. (However, should
|
||||
* any extra ones be required, it should be ok to do so, as well as
|
||||
* defining new functions, etc.
|
||||
*
|
||||
* To add a new test, call AddTest with the following arguments: the
|
||||
* CSS font-family string, the gfxFontStyle, an enum (either S_ASCII
|
||||
* or S_UTF8) indicating the string type, and then the text string
|
||||
* itself as a string literal. Unfortunately there is no good way to
|
||||
* embed UTF8 directly into C code, so hex literals will need to be
|
||||
* placed in the string. Because of the way \x is parsed things like
|
||||
* "\xabcd" won't work -- you have to do "\xab""cd". "\xab\x01\x03"
|
||||
* will work fine, though.
|
||||
*
|
||||
* The result of AddTest should be assigned to the variable t; after
|
||||
* AddTest, one or more calls to t->Expect() should be added to define
|
||||
* the expected result. Multiple Expect() calls in a row for the same
|
||||
* platform mean that the resulting glyph/font selection items needs
|
||||
* to have as many items as there are Expect() calls. (See below for
|
||||
* examples.)
|
||||
*
|
||||
* The arguments to Expect are:
|
||||
*
|
||||
* platform - a string identifying the platform.
|
||||
* Valid strings are "win32", "macosx", and "gtk2-pango".
|
||||
* font - a string (UTF8) giving the unique name of the font.
|
||||
* See below for how the unique name is constructed.
|
||||
* glyphs - a set of glyph IDs that are expected.
|
||||
* This array is constructed using a GLYPHS() macro.
|
||||
*
|
||||
* GLYPHS() is just a #define for LiteralArray, which is defined
|
||||
* in gfxFontSelectionTest.cpp -- if you need more array elements
|
||||
* than available, just extend LiteralArray with a new constructor
|
||||
* with the required number of unsigned longs.
|
||||
*
|
||||
* The unique font name is a platform-specific constructed string for
|
||||
* (mostly) identifying a font. On Mac, it's created by taking the
|
||||
* Postscript name of the font. On Windows, it's created by taking
|
||||
* the family name, and then appending attributes such as ":Bold",
|
||||
* ":Italic", etc.
|
||||
*
|
||||
* The easiest way to create a test is to add a call to AddTest, and
|
||||
* then run the test. The output will include a list like:
|
||||
*
|
||||
* ==== Test 1
|
||||
* expected:
|
||||
* Run[ 0]: 'Verdana' 73 82 82
|
||||
* Run[ 1]: 'MS UI Gothic' 19401
|
||||
* Run[ 2]: 'Verdana' 69 68 85
|
||||
* Test 1 failed
|
||||
*
|
||||
* This gives you the information needed for the calls to Expect() --
|
||||
* the unique name, and the glyphs. Appropriate calls to expect for
|
||||
* the above would be:
|
||||
*
|
||||
* t->Expect ("win32", "Verdana", GLYPHS(73, 82, 82));
|
||||
* t->Expect ("win32", "MS UI Gothic", GLYPHS(19401));
|
||||
* t->Expect ("win32", "Verdana", GLYPHS(69, 68, 85));
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
SetupTests(nsTArray<TestEntry>& testList)
|
||||
{
|
||||
TestEntry *t;
|
||||
|
||||
/* some common styles */
|
||||
gfxFontStyle style_western_normal_16 (mozilla::gfx::FontStyle::NORMAL,
|
||||
400,
|
||||
0,
|
||||
16.0,
|
||||
NS_Atomize(NS_LITERAL_STRING("en")),
|
||||
0.0,
|
||||
false, false,
|
||||
NS_LITERAL_STRING(""));
|
||||
|
||||
gfxFontStyle style_western_bold_16 (mozilla::gfx::FontStyle::NORMAL,
|
||||
700,
|
||||
0,
|
||||
16.0,
|
||||
NS_Atomize(NS_LITERAL_STRING("en")),
|
||||
0.0,
|
||||
false, false,
|
||||
NS_LITERAL_STRING(""));
|
||||
|
||||
/* Test 0 */
|
||||
t = AddTest (testList, "sans-serif",
|
||||
style_western_normal_16,
|
||||
S_ASCII,
|
||||
"ABCD");
|
||||
|
||||
t->Expect ("win32", "Arial", GLYPHS(36, 37, 38, 39));
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(36, 37, 38, 39));
|
||||
t->Expect ("gtk2-pango", "Albany AMT", GLYPHS(36, 37, 38, 39));
|
||||
|
||||
/* Test 1 */
|
||||
t = AddTest (testList, "verdana,sans-serif",
|
||||
style_western_normal_16,
|
||||
S_UTF8,
|
||||
"foo\xe2\x80\x91""bar");
|
||||
|
||||
t->Expect ("win32", "Verdana", GLYPHS(73, 82, 82));
|
||||
t->Expect ("win32", "Arial Unicode MS", GLYPHS(3236));
|
||||
t->Expect ("win32", "Verdana", GLYPHS(69, 68, 85));
|
||||
|
||||
t->Expect ("macosx", "Verdana", GLYPHS(73, 82, 82));
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(587));
|
||||
t->Expect ("macosx", "Verdana", GLYPHS(69, 68, 85));
|
||||
|
||||
/* Test 2 */
|
||||
t = AddTest (testList, "sans-serif",
|
||||
style_western_bold_16,
|
||||
S_ASCII,
|
||||
"ABCD");
|
||||
|
||||
t->Expect ("win32", "Arial:700", GLYPHS(36, 37, 38, 39));
|
||||
t->Expect ("macosx", "Helvetica-Bold", GLYPHS(36, 37, 38, 39));
|
||||
t->Expect ("gtk2-pango", "Albany AMT Bold", GLYPHS(36, 37, 38, 39));
|
||||
|
||||
/* Test 3: RTL Arabic with a ligature and leading and trailing whitespace */
|
||||
t = AddTest (testList, "sans-serif",
|
||||
style_western_normal_16,
|
||||
S_UTF8,
|
||||
" \xd8\xaa\xd9\x85 ");
|
||||
t->SetRTL();
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(3));
|
||||
t->Expect ("macosx", "ArialMT", GLYPHS(919, 993));
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(3));
|
||||
t->Expect ("win32", "Arial", GLYPHS(3, 919, 994, 3));
|
||||
|
||||
/* Test 4: LTR Arabic with leading and trailing whitespace */
|
||||
t = AddTest (testList, "sans-serif",
|
||||
style_western_normal_16,
|
||||
S_UTF8,
|
||||
" \xd9\x85\xd8\xaa ");
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(3));
|
||||
t->Expect ("macosx", "ArialMT", GLYPHS(993, 919));
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(3));
|
||||
t->Expect ("win32", "Arial", GLYPHS(3, 994, 919, 3));
|
||||
|
||||
/* Test 5: RTL ASCII with leading whitespace */
|
||||
t = AddTest (testList, "sans-serif",
|
||||
style_western_normal_16,
|
||||
S_ASCII,
|
||||
" ab");
|
||||
t->SetRTL();
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(3, 68, 69));
|
||||
t->Expect ("win32", "Arial", GLYPHS(3, 68, 69));
|
||||
t->Expect ("gtk2-pango", "Albany AMT", GLYPHS(3, 68, 69));
|
||||
|
||||
/* Test 6: RTL ASCII with trailing whitespace */
|
||||
t = AddTest (testList, "sans-serif",
|
||||
style_western_normal_16,
|
||||
S_ASCII,
|
||||
"ab ");
|
||||
t->SetRTL();
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(68, 69, 3));
|
||||
t->Expect ("win32", "Arial", GLYPHS(68, 69, 3));
|
||||
t->Expect ("gtk2-pango", "Albany AMT", GLYPHS(68, 69, 3));
|
||||
|
||||
/* Test 7: Simple ASCII ligature */
|
||||
/* Do we have a Windows font with ligatures? Can we use DejaVu Sans? */
|
||||
t = AddTest (testList, "sans-serif",
|
||||
style_western_normal_16,
|
||||
S_ASCII,
|
||||
"fi");
|
||||
t->Expect ("macosx", "Helvetica", GLYPHS(192));
|
||||
t->Expect ("win32", "Arial", GLYPHS(73, 76));
|
||||
|
||||
/* Test 8: DEVANAGARI VOWEL I reordering */
|
||||
/* The glyph for DEVANAGARI VOWEL I 2367 (101) is displayed before the glyph for 2361 (99) */
|
||||
t = AddTest (testList, "sans-serif",
|
||||
style_western_normal_16,
|
||||
S_UTF8,
|
||||
"\xe0\xa4\x9a\xe0\xa4\xbe\xe0\xa4\xb9\xe0\xa4\xbf\xe0\xa4\x8f"); // 2330 2366 2361 2367 2319
|
||||
t->Expect ("macosx", "DevanagariMT", GLYPHS(71, 100, 101, 99, 60));
|
||||
t->Expect ("win32", "Mangal", GLYPHS(133, 545, 465, 161, 102));
|
||||
|
||||
// Disabled Test 9 & 10 because these appear to vary on mac
|
||||
|
||||
/* Test 9: NWJ test */
|
||||
//t = AddTest (testList, "Kartika",
|
||||
// style_western_normal_16,
|
||||
// S_UTF8,
|
||||
// "\xe0\xb4\xb3\xe0\xb5\x8d\xe2\x80\x8d");
|
||||
//t->Expect ("macosx", "MalayalamMN", GLYPHS(360));
|
||||
//t->Expect ("win32", "Kartika", GLYPHS(332));
|
||||
|
||||
/* Test 10: NWJ fallback test */
|
||||
/* it isn't clear what we should actually do in this case. Ideally
|
||||
we would have the same results as the previous test, but because
|
||||
we use sans-serif (i.e. Arial) CSS says we should should really
|
||||
use Arial for U+200D.
|
||||
*/
|
||||
//t = AddTest (testList, "sans-serif",
|
||||
// style_western_normal_16,
|
||||
// S_UTF8,
|
||||
// "\xe0\xb4\xb3\xe0\xb5\x8d\xe2\x80\x8d");
|
||||
// Disabled because these appear to vary
|
||||
//t->Expect ("macosx", "MalayalamMN", GLYPHS(360));
|
||||
//t->Expect ("win32", "Kartika", GLYPHS(332));
|
||||
}
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "gtest/gtest.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsString.h"
|
||||
#include "nsDependentString.h"
|
||||
|
||||
#include "prinrval.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#include "gfxFontTest.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
struct TestEntry {
|
||||
const char* mFamilies;
|
||||
const char* mString;
|
||||
};
|
||||
|
||||
TestEntry testList[] = {
|
||||
#include "per-word-runs.h"
|
||||
{ nullptr, nullptr } // terminator
|
||||
};
|
||||
|
||||
static already_AddRefed<gfxContext>
|
||||
MakeContext ()
|
||||
{
|
||||
const int size = 200;
|
||||
|
||||
RefPtr<DrawTarget> drawTarget = gfxPlatform::GetPlatform()->
|
||||
CreateOffscreenContentDrawTarget(IntSize(size, size),
|
||||
SurfaceFormat::B8G8R8X8);
|
||||
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(drawTarget);
|
||||
if (!ctx) {
|
||||
MOZ_CRASH("gfxContext creation failed");
|
||||
}
|
||||
|
||||
return ctx.forget();
|
||||
}
|
||||
|
||||
const char* lastFamilies = nullptr;
|
||||
|
||||
static void
|
||||
RunTest (TestEntry *test, gfxContext *ctx) {
|
||||
RefPtr<gfxFontGroup> fontGroup;
|
||||
if (!lastFamilies || strcmp(lastFamilies, test->mFamilies)) {
|
||||
gfxFontStyle style_western_normal_16 (mozilla::gfx::FontStyle::NORMAL,
|
||||
400,
|
||||
0,
|
||||
16.0,
|
||||
NS_Atomize(NS_LITERAL_STRING("en")),
|
||||
0.0,
|
||||
false, false,
|
||||
NS_LITERAL_STRING(""));
|
||||
|
||||
fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->mFamilies), &style_western_normal_16, nullptr, nullptr, 1.0);
|
||||
}
|
||||
|
||||
RefPtr<gfxTextRun> textRun;
|
||||
uint32_t i;
|
||||
bool isASCII = true;
|
||||
for (i = 0; test->mString[i]; ++i) {
|
||||
if (test->mString[i] & 0x80) {
|
||||
isASCII = false;
|
||||
}
|
||||
}
|
||||
gfxTextRunFactory::Parameters params = {
|
||||
ctx, nullptr, nullptr, nullptr, 0, 60
|
||||
};
|
||||
uint32_t flags = gfxTextRunFactory::TEXT_IS_PERSISTENT;
|
||||
uint32_t length;
|
||||
gfxFontTestStore::NewStore();
|
||||
if (isASCII) {
|
||||
flags |= gfxTextRunFactory::TEXT_IS_ASCII |
|
||||
gfxTextRunFactory::TEXT_IS_8BIT;
|
||||
length = strlen(test->mString);
|
||||
textRun = fontGroup->MakeTextRun(
|
||||
reinterpret_cast<const uint8_t*>(test->mString), length, ¶ms, flags);
|
||||
} else {
|
||||
NS_ConvertUTF8toUTF16 str(nsDependentCString(test->mString));
|
||||
length = str.Length();
|
||||
textRun = fontGroup->MakeTextRun(str.get(), length, ¶ms, flags);
|
||||
}
|
||||
|
||||
// Should we test drawing?
|
||||
// textRun->Draw(ctx, gfxPoint(0,0), 0, length, nullptr, nullptr, nullptr);
|
||||
|
||||
textRun->GetAdvanceWidth(0, length, nullptr);
|
||||
gfxFontTestStore::DeleteStore();
|
||||
}
|
||||
|
||||
uint32_t iterations = 1;
|
||||
|
||||
TEST(Gfx, TextRunPref) {
|
||||
RefPtr<gfxContext> context = MakeContext();
|
||||
|
||||
// Start timing
|
||||
PRIntervalTime start = PR_IntervalNow();
|
||||
|
||||
for (uint32_t i = 0; i < iterations; ++i) {
|
||||
for (uint test = 0;
|
||||
test < ArrayLength(testList) - 1;
|
||||
test++)
|
||||
{
|
||||
RunTest(&testList[test], context);
|
||||
}
|
||||
}
|
||||
|
||||
PRIntervalTime end = PR_IntervalNow();
|
||||
|
||||
printf("Elapsed time (ms): %d\n", PR_IntervalToMilliseconds(end - start));
|
||||
|
||||
}
|
||||
|
|
@ -25,15 +25,9 @@ UNIFIED_SOURCES += [
|
|||
'TestRegion.cpp',
|
||||
'TestSkipChars.cpp',
|
||||
'TestSwizzle.cpp',
|
||||
# Hangs on linux in ApplyGdkScreenFontOptions
|
||||
#'gfxFontSelectionTest.cpp',
|
||||
'TestTextureCompatibility.cpp',
|
||||
'TestTextures.cpp',
|
||||
'TestTreeTraversal.cpp',
|
||||
# Test works but it doesn't assert anything
|
||||
#'gfxTextRunPerfTest.cpp',
|
||||
# Bug 1179287 - PGO bustage on Linux
|
||||
#'TestTiledLayerBuffer.cpp',
|
||||
'TestVsync.cpp',
|
||||
]
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,8 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
#include "gfxFontTest.h"
|
||||
|
||||
gfxFontTestStore* gfxFontTestStore::sCurrentStore = nullptr;
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 GFX_FONT_TEST_H
|
||||
#define GFX_FONT_TEST_H
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "cairo.h"
|
||||
|
||||
struct gfxFontTestItem {
|
||||
gfxFontTestItem(const nsCString& fontName,
|
||||
cairo_glyph_t *cglyphs, int nglyphs)
|
||||
: platformFont(fontName)
|
||||
{
|
||||
glyphs = new cairo_glyph_t[nglyphs];
|
||||
memcpy (glyphs, cglyphs, sizeof(cairo_glyph_t) * nglyphs);
|
||||
num_glyphs = nglyphs;
|
||||
}
|
||||
|
||||
gfxFontTestItem(const gfxFontTestItem& other) {
|
||||
platformFont = other.platformFont;
|
||||
num_glyphs = other.num_glyphs;
|
||||
glyphs = new cairo_glyph_t[num_glyphs];
|
||||
memcpy (glyphs, other.glyphs, sizeof(cairo_glyph_t) * num_glyphs);
|
||||
}
|
||||
|
||||
~gfxFontTestItem() {
|
||||
delete [] glyphs;
|
||||
}
|
||||
|
||||
nsCString platformFont;
|
||||
cairo_glyph_t *glyphs;
|
||||
int num_glyphs;
|
||||
};
|
||||
|
||||
|
||||
class gfxFontTestStore {
|
||||
public:
|
||||
gfxFontTestStore() { }
|
||||
|
||||
void AddItem (const nsCString& fontString,
|
||||
cairo_glyph_t *cglyphs, int nglyphs)
|
||||
{
|
||||
items.AppendElement(gfxFontTestItem(fontString, cglyphs, nglyphs));
|
||||
}
|
||||
|
||||
void AddItem (const nsString& fontString,
|
||||
cairo_glyph_t *cglyphs, int nglyphs)
|
||||
{
|
||||
items.AppendElement(gfxFontTestItem(NS_ConvertUTF16toUTF8(fontString), cglyphs, nglyphs));
|
||||
}
|
||||
|
||||
nsTArray<gfxFontTestItem> items;
|
||||
|
||||
public:
|
||||
static gfxFontTestStore *CurrentStore() {
|
||||
return sCurrentStore;
|
||||
}
|
||||
|
||||
static gfxFontTestStore *NewStore() {
|
||||
if (sCurrentStore)
|
||||
delete sCurrentStore;
|
||||
|
||||
sCurrentStore = new gfxFontTestStore;
|
||||
return sCurrentStore;
|
||||
}
|
||||
|
||||
static void DeleteStore() {
|
||||
if (sCurrentStore)
|
||||
delete sCurrentStore;
|
||||
|
||||
sCurrentStore = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
static gfxFontTestStore *sCurrentStore;
|
||||
};
|
||||
|
||||
|
||||
#endif /* GFX_FONT_TEST_H */
|
||||
|
|
@ -336,9 +336,9 @@ gfxHarfBuzzShaper::GetGlyphHAdvance(hb_codepoint_t glyph) const
|
|||
// glyph must be valid now, because we checked during initialization
|
||||
// that mNumLongHMetrics is > 0, and that the metrics table is large enough
|
||||
// to contain mNumLongHMetrics records
|
||||
const GlyphMetrics* metrics =
|
||||
reinterpret_cast<const GlyphMetrics*>(hb_blob_get_data(mHmtxTable,
|
||||
nullptr));
|
||||
const ::GlyphMetrics* metrics =
|
||||
reinterpret_cast<const ::GlyphMetrics*>(hb_blob_get_data(mHmtxTable,
|
||||
nullptr));
|
||||
return FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
|
||||
uint16_t(metrics->metrics[glyph].advanceWidth));
|
||||
}
|
||||
|
|
@ -362,9 +362,9 @@ gfxHarfBuzzShaper::GetGlyphVAdvance(hb_codepoint_t glyph) const
|
|||
// glyph must be valid now, because we checked during initialization
|
||||
// that mNumLongVMetrics is > 0, and that the metrics table is large enough
|
||||
// to contain mNumLongVMetrics records
|
||||
const GlyphMetrics* metrics =
|
||||
reinterpret_cast<const GlyphMetrics*>(hb_blob_get_data(mVmtxTable,
|
||||
nullptr));
|
||||
const ::GlyphMetrics* metrics =
|
||||
reinterpret_cast<const ::GlyphMetrics*>(hb_blob_get_data(mVmtxTable,
|
||||
nullptr));
|
||||
return FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
|
||||
uint16_t(metrics->metrics[glyph].advanceWidth));
|
||||
}
|
||||
|
|
@ -465,8 +465,8 @@ gfxHarfBuzzShaper::GetGlyphVOrigin(hb_codepoint_t aGlyph,
|
|||
return;
|
||||
}
|
||||
|
||||
const GlyphMetrics* metrics =
|
||||
reinterpret_cast<const GlyphMetrics*>
|
||||
const ::GlyphMetrics* metrics =
|
||||
reinterpret_cast<const ::GlyphMetrics*>
|
||||
(hb_blob_get_data(mVmtxTable, nullptr));
|
||||
int16_t lsb;
|
||||
if (aGlyph < hb_codepoint_t(mNumLongVMetrics)) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "harfbuzz/hb.h"
|
||||
#include "harfbuzz/hb-ot.h"
|
||||
|
||||
#define FloatToFixed(f) (65536 * (f))
|
||||
#define FixedToFloat(f) ((f) * (1.0 / 65536.0))
|
||||
|
||||
using namespace mozilla;
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@
|
|||
#include "nsCharTraits.h"
|
||||
#include "harfbuzz/hb.h"
|
||||
|
||||
using namespace mozilla::unicode;
|
||||
|
||||
#define MOD(sp) ((sp) % PAREN_STACK_DEPTH)
|
||||
#define LIMIT_INC(sp) (((sp) < PAREN_STACK_DEPTH)? (sp) + 1 : PAREN_STACK_DEPTH)
|
||||
#define INC(sp,count) (MOD((sp) + (count)))
|
||||
|
|
|
|||
|
|
@ -616,11 +616,17 @@ gfxTextRun::Draw(Range aRange, gfxPoint aPt, const DrawParams& aParams) const
|
|||
HasNonOpaqueNonTransparentColor(aParams.context, currentColor) &&
|
||||
HasSyntheticBoldOrColor(this, aRange)) {
|
||||
needToRestore = true;
|
||||
// measure text, use the bounding box
|
||||
// Measure text; use the bounding box to determine the area we need
|
||||
// to buffer.
|
||||
gfxTextRun::Metrics metrics = MeasureText(
|
||||
aRange, gfxFont::LOOSE_INK_EXTENTS,
|
||||
aParams.context->GetDrawTarget(), aParams.provider);
|
||||
metrics.mBoundingBox.MoveBy(aPt);
|
||||
if (IsRightToLeft()) {
|
||||
metrics.mBoundingBox.MoveBy(gfxPoint(aPt.x - metrics.mAdvanceWidth,
|
||||
aPt.y));
|
||||
} else {
|
||||
metrics.mBoundingBox.MoveBy(aPt);
|
||||
}
|
||||
syntheticBoldBuffer.PushSolidColor(metrics.mBoundingBox, currentColor,
|
||||
GetAppUnitsPerDevUnit());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ EXPORTS += [
|
|||
'gfxFontFeatures.h',
|
||||
'gfxFontInfoLoader.h',
|
||||
'gfxFontPrefLangList.h',
|
||||
'gfxFontTest.h',
|
||||
'gfxFontUtils.h',
|
||||
'gfxFontVariations.h',
|
||||
'gfxGradientCache.h',
|
||||
|
|
@ -198,7 +197,6 @@ UNIFIED_SOURCES += [
|
|||
'gfxFontFeatures.cpp',
|
||||
'gfxFontInfoLoader.cpp',
|
||||
'gfxFontMissingGlyphs.cpp',
|
||||
'gfxFontTest.cpp',
|
||||
'gfxGlyphExtents.cpp',
|
||||
'gfxGradientCache.cpp',
|
||||
'gfxGraphiteShaper.cpp',
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public:
|
|||
* specified).
|
||||
* Returns true if the semaphore was succesfully decremented, false otherwise.
|
||||
**/
|
||||
bool Wait(Maybe<TimeDuration> aWaitTime = Nothing());
|
||||
bool Wait(const Maybe<TimeDuration>& aWaitTime = Nothing());
|
||||
|
||||
/**
|
||||
* Increments the current value of the semaphore.
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ CrossProcessSemaphore::~CrossProcessSemaphore()
|
|||
}
|
||||
|
||||
bool
|
||||
CrossProcessSemaphore::Wait(Maybe<TimeDuration> aWaitTime)
|
||||
CrossProcessSemaphore::Wait(const Maybe<TimeDuration>& aWaitTime)
|
||||
{
|
||||
MOZ_ASSERT(*mRefCount > 0, "Attempting to wait on a semaphore with zero ref count");
|
||||
int ret;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ CrossProcessSemaphore::~CrossProcessSemaphore()
|
|||
}
|
||||
|
||||
bool
|
||||
CrossProcessSemaphore::Wait(Maybe<TimeDuration> aWaitTime)
|
||||
CrossProcessSemaphore::Wait(const Maybe<TimeDuration>& aWaitTime)
|
||||
{
|
||||
MOZ_CRASH("Cross-process semaphores not allowed on this platform - woah! We should've aborted by now!");
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ CrossProcessSemaphore::~CrossProcessSemaphore()
|
|||
}
|
||||
|
||||
bool
|
||||
CrossProcessSemaphore::Wait(Maybe<TimeDuration> aWaitTime)
|
||||
CrossProcessSemaphore::Wait(const Maybe<TimeDuration>& aWaitTime)
|
||||
{
|
||||
MOZ_ASSERT(mSemaphore, "Improper construction of semaphore.");
|
||||
HRESULT hr = ::WaitForSingleObject(mSemaphore, aWaitTime.isSome() ?
|
||||
|
|
|
|||
|
|
@ -657,6 +657,8 @@ description =
|
|||
description =
|
||||
[PPluginModule::InitCrashReporter]
|
||||
description =
|
||||
[PPluginModule::GetFileName]
|
||||
description =
|
||||
[PPluginScriptableObject::NPN_Evaluate]
|
||||
description =
|
||||
[PPluginScriptableObject::Invalidate]
|
||||
|
|
|
|||
|
|
@ -383,6 +383,10 @@ struct ProxyValueArray
|
|||
for (size_t i = 0; i < PROXY_EXTRA_SLOTS; i++)
|
||||
extraSlots[i] = JS::UndefinedValue();
|
||||
}
|
||||
|
||||
static size_t offsetOfPrivateSlot() {
|
||||
return offsetof(ProxyValueArray, privateSlot);
|
||||
}
|
||||
};
|
||||
|
||||
// All proxies share the same data layout. Following the object's shape and
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ DEFINE_GETTER_FUNCTIONS(ExportEntryObject, moduleRequest, ModuleRequestSlot)
|
|||
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, importName, ImportNameSlot)
|
||||
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, localName, LocalNameSlot)
|
||||
|
||||
DEFINE_ATOM_ACCESSOR_METHOD(ExportEntryObject, exportName)
|
||||
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, exportName)
|
||||
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, moduleRequest)
|
||||
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, importName)
|
||||
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, localName)
|
||||
|
|
|
|||
9
js/src/jit-test/tests/for-of/bug-1341339.js
Normal file
9
js/src/jit-test/tests/for-of/bug-1341339.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
let m = parseModule(`
|
||||
function* values() {}
|
||||
var iterator = values();
|
||||
for (var i=0; i < 10000; ++i) {
|
||||
for (var x of iterator) {}
|
||||
}
|
||||
`);
|
||||
m.declarationInstantiation();
|
||||
m.evaluation();
|
||||
|
|
@ -261,6 +261,24 @@ BaselineCacheIRCompiler::emitGuardProto()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardCompartment()
|
||||
{
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
reader.stubOffset(); // Read global.
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
Address addr(stubAddress(reader.stubOffset()));
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
masm.loadPtr(Address(scratch, ObjectGroup::offsetOfCompartment()), scratch);
|
||||
masm.branchPtr(Assembler::NotEqual, addr, scratch, failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardSpecificObject()
|
||||
{
|
||||
|
|
@ -354,11 +372,11 @@ BaselineCacheIRCompiler::emitLoadDynamicSlotResult()
|
|||
AutoOutputRegister output(*this);
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
|
||||
AutoScratchRegister scratch2(allocator, masm);
|
||||
|
||||
// We're about to return, so it's safe to clobber obj now.
|
||||
masm.load32(stubAddress(reader.stubOffset()), scratch);
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), obj);
|
||||
masm.loadValue(BaseIndex(obj, scratch, TimesOne), output.valueReg());
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch2);
|
||||
masm.loadValue(BaseIndex(scratch2, scratch, TimesOne), output.valueReg());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -159,6 +159,8 @@ GetPropIRGenerator::tryAttachStub()
|
|||
return true;
|
||||
if (tryAttachWindowProxy(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachCrossCompartmentWrapper(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachFunction(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachProxy(obj, objId, id))
|
||||
|
|
@ -435,11 +437,14 @@ EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
|
|||
}
|
||||
|
||||
static void
|
||||
EmitReadSlotReturn(CacheIRWriter& writer, JSObject*, JSObject* holder, Shape* shape)
|
||||
EmitReadSlotReturn(CacheIRWriter& writer, JSObject*, JSObject* holder, Shape* shape,
|
||||
bool wrapResult = false)
|
||||
{
|
||||
// Slot access.
|
||||
if (holder) {
|
||||
MOZ_ASSERT(shape);
|
||||
if (wrapResult)
|
||||
writer.wrapResult();
|
||||
writer.typeMonitorResult();
|
||||
} else {
|
||||
// Normally for this op, the result would have to be monitored by TI.
|
||||
|
|
@ -593,6 +598,78 @@ GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, H
|
|||
MOZ_CRASH("Unreachable");
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachCrossCompartmentWrapper(HandleObject obj, ObjOperandId objId,
|
||||
HandleId id)
|
||||
{
|
||||
// We can only optimize this very wrapper-handler, because others might
|
||||
// have a security policy.
|
||||
if (!IsWrapper(obj) || Wrapper::wrapperHandler(obj) != &CrossCompartmentWrapper::singleton)
|
||||
return false;
|
||||
|
||||
RootedObject unwrapped(cx_, Wrapper::wrappedObject(obj));
|
||||
MOZ_ASSERT(unwrapped == UnwrapOneChecked(obj));
|
||||
|
||||
// If we allowed different zones we would have to wrap strings.
|
||||
if (unwrapped->compartment()->zone() != cx_->compartment()->zone())
|
||||
return false;
|
||||
|
||||
AutoCompartment ac(cx_, unwrapped);
|
||||
|
||||
// The first CCW for iframes is almost always wrapping another WindowProxy
|
||||
// so we optimize for that case as well.
|
||||
bool isWindowProxy = IsWindowProxy(unwrapped);
|
||||
if (isWindowProxy) {
|
||||
MOZ_ASSERT(ToWindowIfWindowProxy(unwrapped) == unwrapped->compartment()->maybeGlobal());
|
||||
unwrapped = cx_->global();
|
||||
MOZ_ASSERT(unwrapped);
|
||||
}
|
||||
|
||||
RootedShape shape(cx_);
|
||||
RootedNativeObject holder(cx_);
|
||||
NativeGetPropCacheability canCache =
|
||||
CanAttachNativeGetProp(cx_, unwrapped, id, &holder, &shape, pc_, canAttachGetter_,
|
||||
isTemporarilyUnoptimizable_);
|
||||
if (canCache != CanAttachReadSlot)
|
||||
return false;
|
||||
|
||||
if (holder) {
|
||||
EnsureTrackPropertyTypes(cx_, holder, id);
|
||||
if (unwrapped == holder) {
|
||||
// See the comment in StripPreliminaryObjectStubs.
|
||||
if (IsPreliminaryObject(unwrapped))
|
||||
preliminaryObjectAction_ = PreliminaryObjectAction::NotePreliminary;
|
||||
else
|
||||
preliminaryObjectAction_ = PreliminaryObjectAction::Unlink;
|
||||
}
|
||||
}
|
||||
|
||||
maybeEmitIdGuard(id);
|
||||
writer.guardIsProxy(objId);
|
||||
writer.guardIsCrossCompartmentWrapper(objId);
|
||||
|
||||
// Load the object wrapped by the CCW
|
||||
ObjOperandId wrapperTargetId = writer.loadWrapperTarget(objId);
|
||||
|
||||
// If the compartment of the wrapped object is different we should fail.
|
||||
writer.guardCompartment(wrapperTargetId, unwrapped->compartment());
|
||||
|
||||
ObjOperandId unwrappedId = wrapperTargetId;
|
||||
if (isWindowProxy) {
|
||||
// For the WindowProxy case also unwrap the inner window.
|
||||
// We avoid loadObject, because storing cross compartment objects in
|
||||
// stubs / JIT code is tricky.
|
||||
writer.guardClass(wrapperTargetId, GuardClassKind::WindowProxy);
|
||||
unwrappedId = writer.loadWrapperTarget(wrapperTargetId);
|
||||
}
|
||||
|
||||
EmitReadSlotResult(writer, unwrapped, holder, shape, unwrappedId);
|
||||
EmitReadSlotReturn(writer, unwrapped, holder, shape, /* wrapResult = */ true);
|
||||
|
||||
trackAttached("CCWSlot");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -157,7 +157,9 @@ extern const char* CacheKindNames[];
|
|||
_(GuardGroup) \
|
||||
_(GuardProto) \
|
||||
_(GuardClass) \
|
||||
_(GuardCompartment) \
|
||||
_(GuardIsProxy) \
|
||||
_(GuardIsCrossCompartmentWrapper) \
|
||||
_(GuardNotDOMProxy) \
|
||||
_(GuardSpecificObject) \
|
||||
_(GuardSpecificAtom) \
|
||||
|
|
@ -172,6 +174,7 @@ extern const char* CacheKindNames[];
|
|||
_(LoadObject) \
|
||||
_(LoadProto) \
|
||||
_(LoadEnclosingEnvironment) \
|
||||
_(LoadWrapperTarget) \
|
||||
\
|
||||
/* See CacheIR.cpp 'DOM proxies' comment. */ \
|
||||
_(LoadDOMExpandoValue) \
|
||||
|
|
@ -228,7 +231,8 @@ extern const char* CacheKindNames[];
|
|||
_(LoadBooleanResult) \
|
||||
\
|
||||
_(TypeMonitorResult) \
|
||||
_(ReturnFromIC)
|
||||
_(ReturnFromIC) \
|
||||
_(WrapResult)
|
||||
|
||||
enum class CacheOp {
|
||||
#define DEFINE_OP(op) op,
|
||||
|
|
@ -483,6 +487,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
void guardIsProxy(ObjOperandId obj) {
|
||||
writeOpWithOperandId(CacheOp::GuardIsProxy, obj);
|
||||
}
|
||||
void guardIsCrossCompartmentWrapper(ObjOperandId obj) {
|
||||
writeOpWithOperandId(CacheOp::GuardIsCrossCompartmentWrapper, obj);
|
||||
}
|
||||
void guardNotDOMProxy(ObjOperandId obj) {
|
||||
writeOpWithOperandId(CacheOp::GuardNotDOMProxy, obj);
|
||||
}
|
||||
|
|
@ -502,6 +509,14 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
writeOpWithOperandId(CacheOp::GuardMagicValue, val);
|
||||
buffer_.writeByte(uint32_t(magic));
|
||||
}
|
||||
void guardCompartment(ObjOperandId obj, JSCompartment* compartment) {
|
||||
writeOpWithOperandId(CacheOp::GuardCompartment, obj);
|
||||
// Add a reference to the compartment's global to keep it alive.
|
||||
addStubField(uintptr_t(compartment->maybeGlobal()), StubField::Type::JSObject);
|
||||
// Use RawWord, because compartments never move and it can't be GCed.
|
||||
addStubField(uintptr_t(compartment), StubField::Type::RawWord);
|
||||
|
||||
}
|
||||
void guardNoDetachedTypedObjects() {
|
||||
writeOp(CacheOp::GuardNoDetachedTypedObjects);
|
||||
}
|
||||
|
|
@ -558,6 +573,13 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
return res;
|
||||
}
|
||||
|
||||
ObjOperandId loadWrapperTarget(ObjOperandId obj) {
|
||||
ObjOperandId res(nextOperandId_++);
|
||||
writeOpWithOperandId(CacheOp::LoadWrapperTarget, obj);
|
||||
writeOperandId(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
ValOperandId loadDOMExpandoValue(ObjOperandId obj) {
|
||||
ValOperandId res(nextOperandId_++);
|
||||
writeOpWithOperandId(CacheOp::LoadDOMExpandoValue, obj);
|
||||
|
|
@ -829,6 +851,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
void returnFromIC() {
|
||||
writeOp(CacheOp::ReturnFromIC);
|
||||
}
|
||||
void wrapResult() {
|
||||
writeOp(CacheOp::WrapResult);
|
||||
}
|
||||
};
|
||||
|
||||
class CacheIRStubInfo;
|
||||
|
|
@ -950,6 +975,7 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator
|
|||
bool tryAttachObjectLength(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachCrossCompartmentWrapper(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachFunction(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
|
||||
bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
|
|
|
|||
|
|
@ -1283,6 +1283,22 @@ CacheIRCompiler::emitGuardIsProxy()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheIRCompiler::emitGuardIsCrossCompartmentWrapper()
|
||||
{
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
Address handlerAddr(obj, ProxyObject::offsetOfHandler());
|
||||
masm.branchPtr(Assembler::NotEqual, handlerAddr, ImmPtr(&CrossCompartmentWrapper::singleton),
|
||||
failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheIRCompiler::emitGuardNotDOMProxy()
|
||||
{
|
||||
|
|
@ -1419,6 +1435,17 @@ CacheIRCompiler::emitLoadEnclosingEnvironment()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheIRCompiler::emitLoadWrapperTarget()
|
||||
{
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
Register reg = allocator.defineRegister(masm, reader.objOperandId());
|
||||
|
||||
masm.loadPtr(Address(obj, ProxyObject::offsetOfValues()), reg);
|
||||
masm.unboxObject(Address(reg, detail::ProxyValueArray::offsetOfPrivateSlot()), reg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheIRCompiler::emitLoadDOMExpandoValue()
|
||||
{
|
||||
|
|
@ -1921,3 +1948,45 @@ CacheIRCompiler::emitLoadTypedObjectResultShared(const Address& fieldAddr, Regis
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CacheIRCompiler::emitWrapResult()
|
||||
{
|
||||
AutoOutputRegister output(*this);
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
Label done;
|
||||
// We only have to wrap objects, because we are in the same zone.
|
||||
masm.branchTestObject(Assembler::NotEqual, output.valueReg(), &done);
|
||||
|
||||
Register obj = output.valueReg().scratchReg();
|
||||
masm.unboxObject(output.valueReg(), obj);
|
||||
|
||||
AllocatableRegisterSet regs(RegisterSet::Volatile());
|
||||
LiveRegisterSet save(regs.asLiveSet());
|
||||
masm.PushRegsInMask(save);
|
||||
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.loadJSContext(scratch);
|
||||
masm.passABIArg(scratch);
|
||||
masm.passABIArg(obj);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, WrapObjectPure));
|
||||
masm.mov(ReturnReg, obj);
|
||||
|
||||
LiveRegisterSet ignore;
|
||||
ignore.add(obj);
|
||||
masm.PopRegsInMaskIgnore(save, ignore);
|
||||
|
||||
// We could not get a wrapper for this object.
|
||||
masm.branchTestPtr(Assembler::Zero, obj, obj, failure->label());
|
||||
|
||||
// We clobbered the output register, so we have to retag.
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, obj, output.valueReg());
|
||||
|
||||
masm.bind(&done);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ namespace jit {
|
|||
_(GuardType) \
|
||||
_(GuardClass) \
|
||||
_(GuardIsProxy) \
|
||||
_(GuardIsCrossCompartmentWrapper) \
|
||||
_(GuardNotDOMProxy) \
|
||||
_(GuardMagicValue) \
|
||||
_(GuardNoUnboxedExpando) \
|
||||
|
|
@ -32,6 +33,7 @@ namespace jit {
|
|||
_(GuardAndGetIndexFromString) \
|
||||
_(LoadProto) \
|
||||
_(LoadEnclosingEnvironment) \
|
||||
_(LoadWrapperTarget) \
|
||||
_(LoadDOMExpandoValue) \
|
||||
_(LoadDOMExpandoValueIgnoreGeneration)\
|
||||
_(LoadUndefinedResult) \
|
||||
|
|
@ -47,7 +49,8 @@ namespace jit {
|
|||
_(LoadDenseElementHoleResult) \
|
||||
_(LoadDenseElementExistsResult) \
|
||||
_(LoadUnboxedArrayElementResult) \
|
||||
_(LoadTypedElementResult)
|
||||
_(LoadTypedElementResult) \
|
||||
_(WrapResult)
|
||||
|
||||
// Represents a Value on the Baseline frame's expression stack. Slot 0 is the
|
||||
// value on top of the stack (the most recently pushed value), slot 1 is the
|
||||
|
|
|
|||
|
|
@ -870,9 +870,12 @@ IonBuilder::processIterators()
|
|||
Vector<MDefinition*, 8, SystemAllocPolicy> worklist;
|
||||
|
||||
for (size_t i = 0; i < iterators_.length(); i++) {
|
||||
if (!worklist.append(iterators_[i]))
|
||||
return abort(AbortReason::Alloc);
|
||||
iterators_[i]->setInWorklist();
|
||||
MDefinition* iter = iterators_[i];
|
||||
if (!iter->isInWorklist()) {
|
||||
if (!worklist.append(iter))
|
||||
return abort(AbortReason::Alloc);
|
||||
iter->setInWorklist();
|
||||
}
|
||||
}
|
||||
|
||||
while (!worklist.empty()) {
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler
|
|||
ObjectGroup* groupStubField(uint32_t offset) {
|
||||
return (ObjectGroup*)readStubWord(offset, StubField::Type::ObjectGroup);
|
||||
}
|
||||
JSCompartment* compartmentStubField(uint32_t offset) {
|
||||
return (JSCompartment*)readStubWord(offset, StubField::Type::RawWord);
|
||||
}
|
||||
jsid idStubField(uint32_t offset) {
|
||||
return mozilla::BitwiseCast<jsid>(readStubWord(offset, StubField::Type::Id));
|
||||
}
|
||||
|
|
@ -490,6 +493,25 @@ IonCacheIRCompiler::emitGuardProto()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonCacheIRCompiler::emitGuardCompartment()
|
||||
{
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
objectStubField(reader.stubOffset()); // Read global.
|
||||
JSCompartment* compartment = compartmentStubField(reader.stubOffset());
|
||||
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
masm.loadPtr(Address(scratch, ObjectGroup::offsetOfCompartment()), scratch);
|
||||
masm.branchPtr(Assembler::NotEqual, scratch, ImmPtr(compartment), failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonCacheIRCompiler::emitGuardSpecificObject()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ struct LoopIterationBound : public TempObject
|
|||
// of the loop header. This will use loop invariant terms and header phis.
|
||||
LinearSum currentSum;
|
||||
|
||||
LoopIterationBound(MBasicBlock* header, MTest* test, LinearSum boundSum, LinearSum currentSum)
|
||||
LoopIterationBound(MBasicBlock* header, MTest* test,
|
||||
const LinearSum& boundSum, const LinearSum& currentSum)
|
||||
: header(header), test(test),
|
||||
boundSum(boundSum), currentSum(currentSum)
|
||||
{
|
||||
|
|
@ -60,7 +61,7 @@ typedef Vector<LoopIterationBound*, 0, SystemAllocPolicy> LoopIterationBoundVect
|
|||
struct SymbolicBound : public TempObject
|
||||
{
|
||||
private:
|
||||
SymbolicBound(LoopIterationBound* loop, LinearSum sum)
|
||||
SymbolicBound(LoopIterationBound* loop, const LinearSum& sum)
|
||||
: loop(loop), sum(sum)
|
||||
{
|
||||
}
|
||||
|
|
@ -74,7 +75,8 @@ struct SymbolicBound : public TempObject
|
|||
// If nullptr, then 'sum' is always valid.
|
||||
LoopIterationBound* loop;
|
||||
|
||||
static SymbolicBound* New(TempAllocator& alloc, LoopIterationBound* loop, LinearSum sum) {
|
||||
static SymbolicBound*
|
||||
New(TempAllocator& alloc, LoopIterationBound* loop, const LinearSum& sum) {
|
||||
return new(alloc) SymbolicBound(loop, sum);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -694,6 +694,38 @@ GetIndexFromString(JSString* str)
|
|||
return int32_t(index);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WrapObjectPure(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(obj);
|
||||
MOZ_ASSERT(cx->compartment() != obj->compartment());
|
||||
|
||||
// From: JSCompartment::getNonWrapperObjectForCurrentCompartment
|
||||
// Note that if the object is same-compartment, but has been wrapped into a
|
||||
// different compartment, we need to unwrap it and return the bare same-
|
||||
// compartment object. Note again that windows are always wrapped by a
|
||||
// WindowProxy even when same-compartment so take care not to strip this
|
||||
// particular wrapper.
|
||||
obj = UncheckedUnwrap(obj, /* stopAtWindowProxy = */ true);
|
||||
if (cx->compartment() == obj->compartment()) {
|
||||
MOZ_ASSERT(!IsWindow(obj));
|
||||
JS::ExposeObjectToActiveJS(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Try to Lookup an existing wrapper for this object. We assume that
|
||||
// if we can find such a wrapper, not calling preWrap is correct.
|
||||
if (WrapperMap::Ptr p = cx->compartment()->lookupWrapper(obj)) {
|
||||
JSObject* wrapped = &p->value().get().toObject();
|
||||
|
||||
// Ensure the wrapper is still exposed.
|
||||
JS::ExposeObjectToActiveJS(wrapped);
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
DebugPrologue(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool* mustReturn)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -680,6 +680,8 @@ void PostGlobalWriteBarrier(JSRuntime* rt, JSObject* obj);
|
|||
// is not an index in this range, return -1.
|
||||
int32_t GetIndexFromString(JSString* str);
|
||||
|
||||
JSObject* WrapObjectPure(JSContext* cx, JSObject* obj);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
DebugPrologue(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool* mustReturn);
|
||||
MOZ_MUST_USE bool
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
/* Note: Aborts on OOM. */
|
||||
class JSAPITestString {
|
||||
js::Vector<char, 0, js::SystemAllocPolicy> chars;
|
||||
|
||||
public:
|
||||
JSAPITestString() {}
|
||||
explicit JSAPITestString(const char* s) { *this += s; }
|
||||
|
|
@ -33,21 +34,34 @@ class JSAPITestString {
|
|||
const char* end() const { return chars.end(); }
|
||||
size_t length() const { return chars.length(); }
|
||||
|
||||
JSAPITestString & operator +=(const char* s) {
|
||||
JSAPITestString& operator +=(const char* s) {
|
||||
if (!chars.append(s, strlen(s)))
|
||||
abort();
|
||||
return *this;
|
||||
}
|
||||
|
||||
JSAPITestString & operator +=(const JSAPITestString& s) {
|
||||
JSAPITestString& operator +=(const JSAPITestString& s) {
|
||||
if (!chars.append(s.begin(), s.length()))
|
||||
abort();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
inline JSAPITestString operator+(JSAPITestString a, const char* b) { return a += b; }
|
||||
inline JSAPITestString operator+(JSAPITestString a, const JSAPITestString& b) { return a += b; }
|
||||
inline JSAPITestString
|
||||
operator+(const JSAPITestString& a, const char* b)
|
||||
{
|
||||
JSAPITestString result = a;
|
||||
result += b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline JSAPITestString
|
||||
operator+(const JSAPITestString& a, const JSAPITestString& b)
|
||||
{
|
||||
JSAPITestString result = a;
|
||||
result += b;
|
||||
return result;
|
||||
}
|
||||
|
||||
class JSAPITest
|
||||
{
|
||||
|
|
@ -206,7 +220,11 @@ class JSAPITest
|
|||
return fail(JSAPITestString("CHECK failed: " #expr), __FILE__, __LINE__); \
|
||||
} while (false)
|
||||
|
||||
bool fail(JSAPITestString msg = JSAPITestString(), const char* filename = "-", int lineno = 0) {
|
||||
bool fail(const JSAPITestString& msg = JSAPITestString(),
|
||||
const char* filename = "-",
|
||||
int lineno = 0)
|
||||
{
|
||||
JSAPITestString message = msg;
|
||||
if (JS_IsExceptionPending(cx)) {
|
||||
js::gc::AutoSuppressGC gcoff(cx);
|
||||
JS::RootedValue v(cx);
|
||||
|
|
@ -216,11 +234,12 @@ class JSAPITest
|
|||
if (s) {
|
||||
JSAutoByteString bytes(cx, s);
|
||||
if (!!bytes)
|
||||
msg += bytes.ptr();
|
||||
message += bytes.ptr();
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s:%d:%.*s\n", filename, lineno, (int) msg.length(), msg.begin());
|
||||
msgs += msg;
|
||||
fprintf(stderr, "%s:%d:%.*s\n",
|
||||
filename, lineno, int(message.length()), message.begin());
|
||||
msgs += message;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -652,6 +652,10 @@ struct JSCompartment
|
|||
return crossCompartmentWrappers.lookup(js::CrossCompartmentKey(wrapped));
|
||||
}
|
||||
|
||||
js::WrapperMap::Ptr lookupWrapper(JSObject* obj) const {
|
||||
return crossCompartmentWrappers.lookup(js::CrossCompartmentKey(obj));
|
||||
}
|
||||
|
||||
void removeWrapper(js::WrapperMap::Ptr p) {
|
||||
crossCompartmentWrappers.remove(p);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@
|
|||
|
||||
skip script ecma_6/String/normalize-generateddata-input.js # input data for other test
|
||||
|
||||
# jsreftest times out on Android when the complete test262 test suite is enabled.
|
||||
skip-if(Android) include test262/jstests.list
|
||||
|
||||
# Times out on arm and cgc builds.
|
||||
slow script test262/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js
|
||||
slow script test262/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js
|
||||
|
|
@ -31,6 +28,14 @@ skip script test262/language/expressions/yield/iter-value-specified.js
|
|||
skip script test262/language/expressions/yield/iter-value-unspecified.js
|
||||
|
||||
|
||||
#########################################################################
|
||||
# Test262 tests disabled when features are only conditionally available #
|
||||
#########################################################################
|
||||
|
||||
skip-if(!Array.prototype.values) script test262/built-ins/Array/prototype/Symbol.iterator.js
|
||||
skip-if(!Array.prototype.values) include test262/built-ins/Array/prototype/values/jstests.list
|
||||
|
||||
|
||||
#####################################
|
||||
# Test262 tests disabled on browser #
|
||||
#####################################
|
||||
|
|
|
|||
|
|
@ -443,6 +443,10 @@ class ObjectGroup : public gc::TenuredCell
|
|||
return offsetof(ObjectGroup, proto_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfCompartment() {
|
||||
return offsetof(ObjectGroup, compartment_);
|
||||
}
|
||||
|
||||
static inline uint32_t offsetOfAddendum() {
|
||||
return offsetof(ObjectGroup, addendum_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,18 @@ AllocateCodeSegment(JSContext* cx, uint32_t codeLength)
|
|||
codeLength = JS_ROUNDUP(codeLength, ExecutableCodePageSize);
|
||||
|
||||
void* p = AllocateExecutableMemory(codeLength, ProtectionSetting::Writable);
|
||||
|
||||
// If the allocation failed and the embedding gives us a last-ditch attempt
|
||||
// to purge all memory (which, in gecko, does a purging GC/CC/GC), do that
|
||||
// then retry the allocation.
|
||||
if (!p) {
|
||||
JSRuntime* rt = cx->runtime();
|
||||
if (rt->largeAllocationFailureCallback) {
|
||||
rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData);
|
||||
p = AllocateExecutableMemory(codeLength, ProtectionSetting::Writable);
|
||||
}
|
||||
}
|
||||
|
||||
if (!p) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "nsJSUtils.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "GeckoProfiler.h"
|
||||
|
||||
#include "base/histogram.h"
|
||||
|
||||
|
|
@ -1305,6 +1306,9 @@ XRE_XPCShellMain(int argc, char** argv, char** envp,
|
|||
UniquePtr<base::StatisticsRecorder> telStats =
|
||||
MakeUnique<base::StatisticsRecorder>();
|
||||
|
||||
char aLocal;
|
||||
profiler_init(&aLocal);
|
||||
|
||||
if (PR_GetEnv("MOZ_CHAOSMODE")) {
|
||||
ChaosFeature feature = ChaosFeature::Any;
|
||||
long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
|
||||
|
|
@ -1652,6 +1656,10 @@ XRE_XPCShellMain(int argc, char** argv, char** envp,
|
|||
CrashReporter::UnsetExceptionHandler();
|
||||
#endif
|
||||
|
||||
// This must precede NS_LogTerm(), otherwise xpcshell return non-zero
|
||||
// during some tests, which causes failures.
|
||||
profiler_shutdown();
|
||||
|
||||
NS_LogTerm();
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -3,9 +3,14 @@
|
|||
<script>
|
||||
function loadHandler() {
|
||||
var outer = document.getElementById("outer");
|
||||
var inner = document.createElement('iframe');
|
||||
var inner = document.createElement("iframe");
|
||||
inner.height = "1px";
|
||||
outer.contentDocument.body.appendChild(inner);
|
||||
|
||||
// Flush reflow inside our inner iframe. This ensures that our inner.height
|
||||
// tweak further down will actually invoke the resize handler.
|
||||
inner.contentWindow.offsetTop;
|
||||
|
||||
// Set up resize handler (which ends the test, one way or another)
|
||||
inner.contentWindow.onresize = () => {
|
||||
outer.remove();
|
||||
|
|
@ -13,7 +18,7 @@ function loadHandler() {
|
|||
};
|
||||
|
||||
// Trigger the resize handler:
|
||||
inner.height = '0px';
|
||||
inner.height = "5px";
|
||||
inner.offsetTop;
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
18
layout/reftests/text/color-opacity-rtl-1-ref.html
Normal file
18
layout/reftests/text/color-opacity-rtl-1-ref.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<title>Mozilla bug 1318539</title>
|
||||
<style>
|
||||
.ref {
|
||||
font-family: EmojiOne Mozilla, Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji, sans-serif;
|
||||
font-size: 48px;
|
||||
opacity: 0.5;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="ref">
|
||||
(😂😁😀)
|
||||
</body>
|
||||
</html>
|
||||
17
layout/reftests/text/color-opacity-rtl-1.html
Normal file
17
layout/reftests/text/color-opacity-rtl-1.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<title>Mozilla bug 1318539</title>
|
||||
<style>
|
||||
.test {
|
||||
font-family: EmojiOne Mozilla, Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji, sans-serif;
|
||||
font-size: 48px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body dir=rtl class="test">
|
||||
(😀😁😂)
|
||||
</body>
|
||||
</html>
|
||||
19
layout/reftests/text/color-opacity-rtl-2-ref.html
Normal file
19
layout/reftests/text/color-opacity-rtl-2-ref.html
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<title>Mozilla bug 1318539</title>
|
||||
<style>
|
||||
.ref {
|
||||
font-family: EmojiOne Mozilla, Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji, sans-serif;
|
||||
font-size: 48px;
|
||||
opacity: 0.5;
|
||||
unicode-bidi: bidi-override;
|
||||
direction: ltr;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="ref">
|
||||
ב😀א
|
||||
</body>
|
||||
</html>
|
||||
17
layout/reftests/text/color-opacity-rtl-2.html
Normal file
17
layout/reftests/text/color-opacity-rtl-2.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<title>Mozilla bug 1318539</title>
|
||||
<style>
|
||||
.test {
|
||||
font-family: EmojiOne Mozilla, Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji, sans-serif;
|
||||
font-size: 48px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="test">
|
||||
א😀ב
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -342,3 +342,7 @@ HTTP(..) == space-font-1.html space-font-1-ref.html
|
|||
# handling of highly negative letter-spacing and intrinsic width
|
||||
== negative-letter-spacing-1.html negative-letter-spacing-1-ref.html
|
||||
== segment-break-transformation-1.html segment-break-transformation-1-ref.html
|
||||
|
||||
# color glyphs, opacity, and RTL runs - bug 1318539
|
||||
== color-opacity-rtl-1.html color-opacity-rtl-1-ref.html
|
||||
== color-opacity-rtl-2.html color-opacity-rtl-2-ref.html
|
||||
|
|
|
|||
|
|
@ -389,11 +389,7 @@ nsSVGImageFrame::PaintSVG(gfxContext& aContext,
|
|||
dirtyRect.MoveBy(-rootRect.TopLeft());
|
||||
}
|
||||
|
||||
// XXXbholley - I don't think huge images in SVGs are common enough to
|
||||
// warrant worrying about the responsiveness impact of doing synchronous
|
||||
// decodes. The extra code complexity of determinining when we want to
|
||||
// force sync probably just isn't worth it, so always pass FLAG_SYNC_DECODE
|
||||
uint32_t drawFlags = imgIContainer::FLAG_SYNC_DECODE;
|
||||
uint32_t drawFlags = imgIContainer::FLAG_SYNC_DECODE_IF_FAST;
|
||||
|
||||
if (mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) {
|
||||
// Package up the attributes of this image element which can override the
|
||||
|
|
|
|||
|
|
@ -110,8 +110,9 @@ class runnable_args_func : public detail::runnable_args_base<detail::NoResult>
|
|||
{
|
||||
public:
|
||||
// |explicit| to pacify static analysis when there are no |args|.
|
||||
explicit runnable_args_func(FunType f, Args&&... args)
|
||||
: mFunc(f), mArgs(Forward<Args>(args)...)
|
||||
template<typename... Arguments>
|
||||
explicit runnable_args_func(FunType f, Arguments&&... args)
|
||||
: mFunc(f), mArgs(Forward<Arguments>(args)...)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
|
|
@ -125,10 +126,10 @@ private:
|
|||
};
|
||||
|
||||
template<typename FunType, typename... Args>
|
||||
runnable_args_func<FunType, Args...>*
|
||||
WrapRunnableNM(FunType f, Args... args)
|
||||
runnable_args_func<FunType, typename mozilla::Decay<Args>::Type...>*
|
||||
WrapRunnableNM(FunType f, Args&&... args)
|
||||
{
|
||||
return new runnable_args_func<FunType, Args...>(f, Move(args)...);
|
||||
return new runnable_args_func<FunType, typename mozilla::Decay<Args>::Type...>(f, Forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Ret, typename FunType, typename... Args>
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ protected:
|
|||
}
|
||||
|
||||
std::string
|
||||
CreateOffer(const Maybe<JsepOfferOptions> options = Nothing())
|
||||
CreateOffer(const Maybe<JsepOfferOptions>& options = Nothing())
|
||||
{
|
||||
JsepOfferOptions defaultOptions;
|
||||
const JsepOfferOptions& optionsRef = options ? *options : defaultOptions;
|
||||
|
|
@ -408,7 +408,7 @@ protected:
|
|||
return false;
|
||||
}
|
||||
|
||||
// We don't check things like mBundleLevel, since that can change without
|
||||
// We don't check things like BundleLevel(), since that can change without
|
||||
// any changes to the transport, which is what we're really interested in.
|
||||
|
||||
if (p1.mSending.get() != p2.mSending.get()) {
|
||||
|
|
@ -532,7 +532,7 @@ protected:
|
|||
static const uint32_t ALL_CHECKS = CHECK_SUCCESS | CHECK_TRACKS;
|
||||
|
||||
void OfferAnswer(uint32_t checkFlags = ALL_CHECKS,
|
||||
const Maybe<JsepOfferOptions> options = Nothing()) {
|
||||
const Maybe<JsepOfferOptions>& options = Nothing()) {
|
||||
std::string offer = CreateOffer(options);
|
||||
SetLocalOffer(offer, checkFlags);
|
||||
SetRemoteOffer(offer, checkFlags);
|
||||
|
|
@ -922,10 +922,10 @@ protected:
|
|||
|
||||
for (JsepTrackPair& pair : pairs) {
|
||||
if (types.size() == 1) {
|
||||
ASSERT_FALSE(pair.mBundleLevel.isSome()) << context;
|
||||
ASSERT_FALSE(pair.HasBundleLevel()) << context;
|
||||
} else {
|
||||
ASSERT_TRUE(pair.mBundleLevel.isSome()) << context;
|
||||
ASSERT_EQ(0U, *pair.mBundleLevel) << context;
|
||||
ASSERT_TRUE(pair.HasBundleLevel()) << context;
|
||||
ASSERT_EQ(0U, pair.BundleLevel()) << context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1637,10 +1637,10 @@ TEST_P(JsepSessionTest, RenegotiationBothRemoveTrack)
|
|||
ASSERT_EQ(oldPair.mLevel, newPair.mLevel);
|
||||
ASSERT_EQ(oldPair.mSending.get(), newPair.mSending.get());
|
||||
ASSERT_EQ(oldPair.mReceiving.get(), newPair.mReceiving.get());
|
||||
ASSERT_TRUE(oldPair.mBundleLevel.isSome());
|
||||
ASSERT_TRUE(newPair.mBundleLevel.isSome());
|
||||
ASSERT_EQ(0U, *oldPair.mBundleLevel);
|
||||
ASSERT_EQ(1U, *newPair.mBundleLevel);
|
||||
ASSERT_TRUE(oldPair.HasBundleLevel());
|
||||
ASSERT_TRUE(newPair.HasBundleLevel());
|
||||
ASSERT_EQ(0U, oldPair.BundleLevel());
|
||||
ASSERT_EQ(1U, newPair.BundleLevel());
|
||||
}
|
||||
|
||||
ASSERT_EQ(answererPairs.size(), newAnswererPairs.size() + 1);
|
||||
|
|
@ -1651,10 +1651,10 @@ TEST_P(JsepSessionTest, RenegotiationBothRemoveTrack)
|
|||
ASSERT_EQ(oldPair.mLevel, newPair.mLevel);
|
||||
ASSERT_EQ(oldPair.mSending.get(), newPair.mSending.get());
|
||||
ASSERT_EQ(oldPair.mReceiving.get(), newPair.mReceiving.get());
|
||||
ASSERT_TRUE(oldPair.mBundleLevel.isSome());
|
||||
ASSERT_TRUE(newPair.mBundleLevel.isSome());
|
||||
ASSERT_EQ(0U, *oldPair.mBundleLevel);
|
||||
ASSERT_EQ(1U, *newPair.mBundleLevel);
|
||||
ASSERT_TRUE(oldPair.HasBundleLevel());
|
||||
ASSERT_TRUE(newPair.BundleLevel());
|
||||
ASSERT_EQ(0U, oldPair.BundleLevel());
|
||||
ASSERT_EQ(1U, newPair.BundleLevel());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2166,8 +2166,8 @@ TEST_P(JsepSessionTest, RenegotiationOffererEnablesBundle)
|
|||
|
||||
for (size_t i = 0; i < newOffererPairs.size(); ++i) {
|
||||
// No bundle initially
|
||||
ASSERT_FALSE(offererPairs[i].mBundleLevel.isSome());
|
||||
ASSERT_FALSE(answererPairs[i].mBundleLevel.isSome());
|
||||
ASSERT_FALSE(offererPairs[i].HasBundleLevel());
|
||||
ASSERT_FALSE(answererPairs[i].HasBundleLevel());
|
||||
if (i != 0) {
|
||||
ASSERT_NE(offererPairs[0].mRtpTransport.get(),
|
||||
offererPairs[i].mRtpTransport.get());
|
||||
|
|
@ -2184,8 +2184,8 @@ TEST_P(JsepSessionTest, RenegotiationOffererEnablesBundle)
|
|||
}
|
||||
|
||||
// Verify that bundle worked after renegotiation
|
||||
ASSERT_TRUE(newOffererPairs[i].mBundleLevel.isSome());
|
||||
ASSERT_TRUE(newAnswererPairs[i].mBundleLevel.isSome());
|
||||
ASSERT_TRUE(newOffererPairs[i].HasBundleLevel());
|
||||
ASSERT_TRUE(newAnswererPairs[i].HasBundleLevel());
|
||||
ASSERT_EQ(newOffererPairs[0].mRtpTransport.get(),
|
||||
newOffererPairs[i].mRtpTransport.get());
|
||||
ASSERT_EQ(newOffererPairs[0].mRtcpTransport.get(),
|
||||
|
|
@ -2229,10 +2229,10 @@ TEST_P(JsepSessionTest, RenegotiationOffererDisablesBundleTransport)
|
|||
ASSERT_EQ(answererPairs.size(), newAnswererPairs.size() + 1);
|
||||
|
||||
for (size_t i = 0; i < newOffererPairs.size(); ++i) {
|
||||
ASSERT_TRUE(newOffererPairs[i].mBundleLevel.isSome());
|
||||
ASSERT_TRUE(newAnswererPairs[i].mBundleLevel.isSome());
|
||||
ASSERT_EQ(1U, *newOffererPairs[i].mBundleLevel);
|
||||
ASSERT_EQ(1U, *newAnswererPairs[i].mBundleLevel);
|
||||
ASSERT_TRUE(newOffererPairs[i].HasBundleLevel());
|
||||
ASSERT_TRUE(newAnswererPairs[i].HasBundleLevel());
|
||||
ASSERT_EQ(1U, newOffererPairs[i].BundleLevel());
|
||||
ASSERT_EQ(1U, newAnswererPairs[i].BundleLevel());
|
||||
ASSERT_EQ(newOffererPairs[0].mRtpTransport.get(),
|
||||
newOffererPairs[i].mRtpTransport.get());
|
||||
ASSERT_EQ(newOffererPairs[0].mRtcpTransport.get(),
|
||||
|
|
@ -2287,10 +2287,10 @@ TEST_P(JsepSessionTest, RenegotiationAnswererDisablesBundleTransport)
|
|||
ASSERT_EQ(answererPairs.size(), newAnswererPairs.size() + 1);
|
||||
|
||||
for (size_t i = 0; i < newOffererPairs.size(); ++i) {
|
||||
ASSERT_TRUE(newOffererPairs[i].mBundleLevel.isSome());
|
||||
ASSERT_TRUE(newAnswererPairs[i].mBundleLevel.isSome());
|
||||
ASSERT_EQ(1U, *newOffererPairs[i].mBundleLevel);
|
||||
ASSERT_EQ(1U, *newAnswererPairs[i].mBundleLevel);
|
||||
ASSERT_TRUE(newOffererPairs[i].HasBundleLevel());
|
||||
ASSERT_TRUE(newAnswererPairs[i].HasBundleLevel());
|
||||
ASSERT_EQ(1U, newOffererPairs[i].BundleLevel());
|
||||
ASSERT_EQ(1U, newAnswererPairs[i].BundleLevel());
|
||||
ASSERT_EQ(newOffererPairs[0].mRtpTransport.get(),
|
||||
newOffererPairs[i].mRtpTransport.get());
|
||||
ASSERT_EQ(newOffererPairs[0].mRtcpTransport.get(),
|
||||
|
|
|
|||
|
|
@ -446,7 +446,7 @@ JsepSessionImpl::SetupOfferMSections(const JsepOfferOptions& options, Sdp* sdp)
|
|||
|
||||
nsresult
|
||||
JsepSessionImpl::SetupOfferMSectionsByType(SdpMediaSection::MediaType mediatype,
|
||||
Maybe<size_t> offerToReceiveMaybe,
|
||||
const Maybe<size_t>& offerToReceiveMaybe,
|
||||
Sdp* sdp)
|
||||
{
|
||||
// Convert the Maybe into a size_t*, since that is more readable, especially
|
||||
|
|
@ -1474,7 +1474,7 @@ JsepSessionImpl::MakeNegotiatedTrackPair(const SdpMediaSection& remote,
|
|||
trackPairOut->mRecvonlySsrc = mRecvonlySsrcs[local.GetLevel()];
|
||||
|
||||
if (usingBundle) {
|
||||
trackPairOut->mBundleLevel = Some(transportLevel);
|
||||
trackPairOut->SetBundleLevel(transportLevel);
|
||||
}
|
||||
|
||||
auto sendTrack = FindTrackByLevel(mLocalTracks, local.GetLevel());
|
||||
|
|
@ -1497,7 +1497,7 @@ JsepSessionImpl::MakeNegotiatedTrackPair(const SdpMediaSection& remote,
|
|||
trackPairOut->mReceiving = recvTrack->mTrack;
|
||||
|
||||
if (receiving &&
|
||||
trackPairOut->mBundleLevel.isSome() &&
|
||||
trackPairOut->HasBundleLevel() &&
|
||||
recvTrack->mTrack->GetSsrcs().empty() &&
|
||||
recvTrack->mTrack->GetMediaType() != SdpMediaSection::kApplication) {
|
||||
MOZ_MTLOG(ML_ERROR, "Bundled m-section has no ssrc attributes. "
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ private:
|
|||
nsresult SetupOfferMSections(const JsepOfferOptions& options, Sdp* sdp);
|
||||
// Non-const so it can assign m-line index to tracks
|
||||
nsresult SetupOfferMSectionsByType(SdpMediaSection::MediaType type,
|
||||
Maybe<size_t> offerToReceive,
|
||||
const Maybe<size_t>& offerToReceive,
|
||||
Sdp* sdp);
|
||||
nsresult BindLocalTracks(SdpMediaSection::MediaType mediatype,
|
||||
Sdp* sdp);
|
||||
|
|
|
|||
|
|
@ -299,12 +299,26 @@ private:
|
|||
struct JsepTrackPair {
|
||||
size_t mLevel;
|
||||
// Is this track pair sharing a transport with another?
|
||||
Maybe<size_t> mBundleLevel;
|
||||
size_t mBundleLevel = SIZE_MAX; // SIZE_MAX if no bundle level
|
||||
uint32_t mRecvonlySsrc;
|
||||
RefPtr<JsepTrack> mSending;
|
||||
RefPtr<JsepTrack> mReceiving;
|
||||
RefPtr<JsepTransport> mRtpTransport;
|
||||
RefPtr<JsepTransport> mRtcpTransport;
|
||||
|
||||
bool HasBundleLevel() const {
|
||||
return mBundleLevel != SIZE_MAX;
|
||||
}
|
||||
|
||||
size_t BundleLevel() const {
|
||||
MOZ_ASSERT(HasBundleLevel());
|
||||
return mBundleLevel;
|
||||
}
|
||||
|
||||
void SetBundleLevel(size_t aBundleLevel) {
|
||||
MOZ_ASSERT(aBundleLevel != SIZE_MAX);
|
||||
mBundleLevel = aBundleLevel;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -93,8 +93,8 @@ public:
|
|||
if (mThread != nullptr) {
|
||||
MonitorAutoUnlock unlock(mMonitor);
|
||||
NS_DispatchToMainThread(
|
||||
WrapRunnableNM<decltype(&ShutdownThread),
|
||||
nsCOMPtr<nsIThread> >(&ShutdownThread, mThread));
|
||||
WrapRunnableNM(&ShutdownThread, nsCOMPtr<nsIThread>(mThread))
|
||||
);
|
||||
mThread = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -328,8 +328,8 @@ MediaPipelineFactory::GetTransportParameters(
|
|||
{
|
||||
*aLevelOut = aTrackPair.mLevel;
|
||||
|
||||
size_t transportLevel = aTrackPair.mBundleLevel.isSome() ?
|
||||
*aTrackPair.mBundleLevel :
|
||||
size_t transportLevel = aTrackPair.HasBundleLevel() ?
|
||||
aTrackPair.BundleLevel() :
|
||||
aTrackPair.mLevel;
|
||||
|
||||
nsresult rv = CreateOrGetTransportFlow(
|
||||
|
|
@ -348,7 +348,7 @@ MediaPipelineFactory::GetTransportParameters(
|
|||
MOZ_ASSERT(aRtcpOut);
|
||||
}
|
||||
|
||||
if (aTrackPair.mBundleLevel.isSome()) {
|
||||
if (aTrackPair.HasBundleLevel()) {
|
||||
bool receiving = aTrack.GetDirection() == sdp::kRecv;
|
||||
|
||||
*aFilterOut = new MediaPipelineFilter;
|
||||
|
|
|
|||
|
|
@ -1159,8 +1159,8 @@ PeerConnectionImpl::GetDatachannelParameters(
|
|||
static_cast<const JsepApplicationCodecDescription*>(codec)->mLocalPort;
|
||||
*remoteport =
|
||||
static_cast<const JsepApplicationCodecDescription*>(codec)->mRemotePort;
|
||||
if (trackPair.mBundleLevel.isSome()) {
|
||||
*level = static_cast<uint16_t>(*trackPair.mBundleLevel);
|
||||
if (trackPair.HasBundleLevel()) {
|
||||
*level = static_cast<uint16_t>(trackPair.BundleLevel());
|
||||
} else {
|
||||
*level = static_cast<uint16_t>(trackPair.mLevel);
|
||||
}
|
||||
|
|
@ -2467,8 +2467,8 @@ PeerConnectionImpl::InsertDTMF(mozilla::dom::RTCRtpSender& sender,
|
|||
state->mLevel = -1;
|
||||
for (auto& trackPair : trackPairs) {
|
||||
if (state->mTrackId.EqualsASCII(trackPair.mSending->GetTrackId().c_str())) {
|
||||
if (trackPair.mBundleLevel.isSome()) {
|
||||
state->mLevel = *trackPair.mBundleLevel;
|
||||
if (trackPair.HasBundleLevel()) {
|
||||
state->mLevel = trackPair.BundleLevel();
|
||||
} else {
|
||||
state->mLevel = trackPair.mLevel;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ MOZ_CrashOOL(const char* aFilename, int aLine, const char* aReason)
|
|||
#ifdef DEBUG
|
||||
MOZ_ReportCrash(aReason, aFilename, aLine);
|
||||
#endif
|
||||
MOZ_CRASH_ANNOTATE(aReason);
|
||||
gMozCrashReason = aReason;
|
||||
MOZ_REALLY_CRASH(aLine);
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ MOZ_CrashPrintf(const char* aFilename, int aLine, const char* aFormat, ...)
|
|||
#ifdef DEBUG
|
||||
MOZ_ReportCrash(sPrintfCrashReason, aFilename, aLine);
|
||||
#endif
|
||||
MOZ_CRASH_ANNOTATE(sPrintfCrashReason);
|
||||
gMozCrashReason = sPrintfCrashReason;
|
||||
MOZ_REALLY_CRASH(aLine);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
* containing indices corresponding to the tuple indices.
|
||||
*
|
||||
* template <typename... Args, size_t... Indices>
|
||||
* void Helper(const Tuple<Args...>& t, IndexSequence<Indices>)
|
||||
* void Helper(const Tuple<Args...>& t, IndexSequence<Indices...>)
|
||||
* {
|
||||
* Foo(Get<Indices>(t)...);
|
||||
* }
|
||||
|
|
|
|||
26
mfbt/Maybe.h
26
mfbt/Maybe.h
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/OperatorNewExtensions.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include <new> // for placement new
|
||||
|
|
@ -82,21 +83,18 @@ struct Nothing { };
|
|||
* whether or not this is still a problem.
|
||||
*/
|
||||
template<class T>
|
||||
class Maybe
|
||||
class MOZ_NON_PARAM Maybe
|
||||
{
|
||||
bool mIsSome;
|
||||
alignas(T) unsigned char mStorage[sizeof(T)];
|
||||
char mIsSome; // not bool -- guarantees minimal space consumption
|
||||
|
||||
// To support |Maybe<const Type>| we give |mStorage| the type |T| with any
|
||||
// const-ness removed. That allows us to |emplace()| an object into
|
||||
// |mStorage|. Since we treat the contained object as having type |T|
|
||||
// everywhere else (both internally, and when exposed via public methods) the
|
||||
// contained object is still treated as const once stored since |const| is
|
||||
// part of |T|'s type signature.
|
||||
typedef typename RemoveCV<T>::Type StorageType;
|
||||
AlignedStorage2<StorageType> mStorage;
|
||||
// GCC fails due to -Werror=strict-aliasing if |mStorage| is directly cast to
|
||||
// T*. Indirecting through these functions addresses the problem.
|
||||
void* data() { return mStorage; }
|
||||
const void* data() const { return mStorage; }
|
||||
|
||||
public:
|
||||
typedef T ValueType;
|
||||
using ValueType = T;
|
||||
|
||||
Maybe() : mIsSome(false) { }
|
||||
~Maybe() { reset(); }
|
||||
|
|
@ -330,13 +328,13 @@ public:
|
|||
T& ref()
|
||||
{
|
||||
MOZ_ASSERT(mIsSome);
|
||||
return *mStorage.addr();
|
||||
return *static_cast<T*>(data());
|
||||
}
|
||||
|
||||
const T& ref() const
|
||||
{
|
||||
MOZ_ASSERT(mIsSome);
|
||||
return *mStorage.addr();
|
||||
return *static_cast<const T*>(data());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -458,7 +456,7 @@ public:
|
|||
void emplace(Args&&... aArgs)
|
||||
{
|
||||
MOZ_ASSERT(!mIsSome);
|
||||
::new (mStorage.addr()) T(Forward<Args>(aArgs)...);
|
||||
::new (KnownNotNull, data()) T(Forward<Args>(aArgs)...);
|
||||
mIsSome = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/OperatorNewExtensions.h"
|
||||
#include "mozilla/TemplateLib.h"
|
||||
|
||||
#include <new> // for placement new
|
||||
|
|
@ -105,7 +106,7 @@ public:
|
|||
{
|
||||
MOZ_ASSERT(state == None);
|
||||
state = Type2State<T>::result;
|
||||
::new (data()) T(Forward<Args>(aArgs)...);
|
||||
::new (KnownNotNull, data()) T(Forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/OperatorNewExtensions.h"
|
||||
#include "mozilla/TemplateLib.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
|
|
@ -179,12 +180,12 @@ struct VariantImplementation<Tag, N, T>
|
|||
|
||||
template<typename Variant>
|
||||
static void copyConstruct(void* aLhs, const Variant& aRhs) {
|
||||
new (aLhs) T(aRhs.template as<T>());
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template as<T>());
|
||||
}
|
||||
|
||||
template<typename Variant>
|
||||
static void moveConstruct(void* aLhs, Variant&& aRhs) {
|
||||
new (aLhs) T(aRhs.template extract<T>());
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template extract<T>());
|
||||
}
|
||||
|
||||
template<typename Variant>
|
||||
|
|
@ -222,7 +223,7 @@ struct VariantImplementation<Tag, N, T, Ts...>
|
|||
template<typename Variant>
|
||||
static void copyConstruct(void* aLhs, const Variant& aRhs) {
|
||||
if (aRhs.template is<T>()) {
|
||||
new (aLhs) T(aRhs.template as<T>());
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template as<T>());
|
||||
} else {
|
||||
Next::copyConstruct(aLhs, aRhs);
|
||||
}
|
||||
|
|
@ -231,7 +232,7 @@ struct VariantImplementation<Tag, N, T, Ts...>
|
|||
template<typename Variant>
|
||||
static void moveConstruct(void* aLhs, Variant&& aRhs) {
|
||||
if (aRhs.template is<T>()) {
|
||||
new (aLhs) T(aRhs.template extract<T>());
|
||||
::new (KnownNotNull, aLhs) T(aRhs.template extract<T>());
|
||||
} else {
|
||||
Next::moveConstruct(aLhs, aRhs);
|
||||
}
|
||||
|
|
@ -485,7 +486,7 @@ public:
|
|||
explicit Variant(RefT&& aT)
|
||||
: tag(Impl::template tag<T>())
|
||||
{
|
||||
new (ptr()) T(Forward<RefT>(aT));
|
||||
::new (KnownNotNull, ptr()) T(Forward<RefT>(aT));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -498,7 +499,7 @@ public:
|
|||
MOZ_IMPLICIT Variant(detail::AsVariantTemporary<RefT>&& aValue)
|
||||
: tag(Impl::template tag<T>())
|
||||
{
|
||||
new (ptr()) T(Move(aValue.mValue));
|
||||
::new (KnownNotNull, ptr()) T(Move(aValue.mValue));
|
||||
}
|
||||
|
||||
/** Copy construction. */
|
||||
|
|
@ -519,7 +520,7 @@ public:
|
|||
Variant& operator=(const Variant& aRhs) {
|
||||
MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
|
||||
this->~Variant();
|
||||
new (this) Variant(aRhs);
|
||||
::new (KnownNotNull, this) Variant(aRhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -527,7 +528,7 @@ public:
|
|||
Variant& operator=(Variant&& aRhs) {
|
||||
MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
|
||||
this->~Variant();
|
||||
new (this) Variant(Move(aRhs));
|
||||
::new (KnownNotNull, this) Variant(Move(aRhs));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -536,7 +537,7 @@ public:
|
|||
Variant& operator=(detail::AsVariantTemporary<T>&& aValue)
|
||||
{
|
||||
this->~Variant();
|
||||
new (this) Variant(Move(aValue));
|
||||
::new (KnownNotNull, this) Variant(Move(aValue));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
|||
277
mfbt/Vector.h
277
mfbt/Vector.h
|
|
@ -147,7 +147,7 @@ struct VectorImpl
|
|||
aV.free_(aV.mBegin);
|
||||
aV.mBegin = newbuf;
|
||||
/* aV.mLength is unchanged. */
|
||||
aV.mCapacity = aNewCap;
|
||||
aV.mTail.mCapacity = aNewCap;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
@ -226,28 +226,30 @@ struct VectorImpl<T, N, AP, true>
|
|||
{
|
||||
MOZ_ASSERT(!aV.usingInlineStorage());
|
||||
MOZ_ASSERT(!CapacityHasExcessSpace<T>(aNewCap));
|
||||
T* newbuf = aV.template pod_realloc<T>(aV.mBegin, aV.mCapacity, aNewCap);
|
||||
T* newbuf =
|
||||
aV.template pod_realloc<T>(aV.mBegin, aV.mTail.mCapacity, aNewCap);
|
||||
if (MOZ_UNLIKELY(!newbuf)) {
|
||||
return false;
|
||||
}
|
||||
aV.mBegin = newbuf;
|
||||
/* aV.mLength is unchanged. */
|
||||
aV.mCapacity = aNewCap;
|
||||
aV.mTail.mCapacity = aNewCap;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
podResizeToFit(Vector<T, N, AP>& aV)
|
||||
{
|
||||
if (aV.usingInlineStorage() || aV.mLength == aV.mCapacity) {
|
||||
if (aV.usingInlineStorage() || aV.mLength == aV.mTail.mCapacity) {
|
||||
return;
|
||||
}
|
||||
T* newbuf = aV.template pod_realloc<T>(aV.mBegin, aV.mCapacity, aV.mLength);
|
||||
T* newbuf =
|
||||
aV.template pod_realloc<T>(aV.mBegin, aV.mTail.mCapacity, aV.mLength);
|
||||
if (MOZ_UNLIKELY(!newbuf)) {
|
||||
return;
|
||||
}
|
||||
aV.mBegin = newbuf;
|
||||
aV.mCapacity = aV.mLength;
|
||||
aV.mTail.mCapacity = aV.mLength;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -278,7 +280,7 @@ struct VectorTesting;
|
|||
template<typename T,
|
||||
size_t MinInlineCapacity = 0,
|
||||
class AllocPolicy = MallocAllocPolicy>
|
||||
class Vector final : private AllocPolicy
|
||||
class MOZ_NON_PARAM Vector final : private AllocPolicy
|
||||
{
|
||||
/* utilities */
|
||||
|
||||
|
|
@ -294,36 +296,40 @@ class Vector final : private AllocPolicy
|
|||
|
||||
/* magic constants */
|
||||
|
||||
static const int kMaxInlineBytes = 1024;
|
||||
|
||||
/* compute constants */
|
||||
|
||||
/*
|
||||
* Consider element size to be 1 for buffer sizing if there are 0 inline
|
||||
* elements. This allows us to compile when the definition of the element
|
||||
* type is not visible here.
|
||||
/**
|
||||
* The maximum space allocated for inline element storage.
|
||||
*
|
||||
* Explicit specialization is only allowed at namespace scope, so in order
|
||||
* to keep everything here, we use a dummy template parameter with partial
|
||||
* specialization.
|
||||
* We reduce space by what the AllocPolicy base class and prior Vector member
|
||||
* fields likely consume to attempt to play well with binary size classes.
|
||||
*/
|
||||
template<int M, int Dummy>
|
||||
struct ElemSize
|
||||
static constexpr size_t kMaxInlineBytes =
|
||||
1024 - (sizeof(AllocPolicy) + sizeof(T*) + sizeof(size_t) + sizeof(size_t));
|
||||
|
||||
/**
|
||||
* The number of T elements of inline capacity built into this Vector. This
|
||||
* is usually |MinInlineCapacity|, but it may be less (or zero!) for large T.
|
||||
*
|
||||
* We use a partially-specialized template (not explicit specialization, which
|
||||
* is only allowed at namespace scope) to compute this value. The benefit is
|
||||
* that |sizeof(T)| need not be computed, and |T| doesn't have to be fully
|
||||
* defined at the time |Vector<T>| appears, if no inline storage is requested.
|
||||
*/
|
||||
template<size_t MinimumInlineCapacity, size_t Dummy>
|
||||
struct ComputeCapacity
|
||||
{
|
||||
static const size_t value = sizeof(T);
|
||||
};
|
||||
template<int Dummy>
|
||||
struct ElemSize<0, Dummy>
|
||||
{
|
||||
static const size_t value = 1;
|
||||
static constexpr size_t value =
|
||||
tl::Min<MinimumInlineCapacity, kMaxInlineBytes / sizeof(T)>::value;
|
||||
};
|
||||
|
||||
static const size_t kInlineCapacity =
|
||||
tl::Min<MinInlineCapacity, kMaxInlineBytes / ElemSize<MinInlineCapacity, 0>::value>::value;
|
||||
template<size_t Dummy>
|
||||
struct ComputeCapacity<0, Dummy>
|
||||
{
|
||||
static constexpr size_t value = 0;
|
||||
};
|
||||
|
||||
/* Calculate inline buffer size; avoid 0-sized array. */
|
||||
static const size_t kInlineBytes =
|
||||
tl::Max<1, kInlineCapacity * ElemSize<MinInlineCapacity, 0>::value>::value;
|
||||
/** The actual inline capacity in number of elements T. This may be zero! */
|
||||
static constexpr size_t kInlineCapacity =
|
||||
ComputeCapacity<MinInlineCapacity, 0>::value;
|
||||
|
||||
/* member data */
|
||||
|
||||
|
|
@ -339,16 +345,84 @@ class Vector final : private AllocPolicy
|
|||
/* Number of elements in the vector. */
|
||||
size_t mLength;
|
||||
|
||||
/* Max number of elements storable in the vector without resizing. */
|
||||
size_t mCapacity;
|
||||
/*
|
||||
* Memory used to store capacity, reserved element count (debug builds only),
|
||||
* and inline storage. The simple "answer" is:
|
||||
*
|
||||
* size_t mCapacity;
|
||||
* #ifdef DEBUG
|
||||
* size_t mReserved;
|
||||
* #endif
|
||||
* alignas(T) unsigned char mBytes[kInlineCapacity * sizeof(T)];
|
||||
*
|
||||
* but there are complications. First, C++ forbids zero-sized arrays that
|
||||
* might result. Second, we don't want zero capacity to affect Vector's size
|
||||
* (even empty classes take up a byte, unless they're base classes).
|
||||
*
|
||||
* Yet again, we eliminate the zero-sized array using partial specialization.
|
||||
* And we eliminate potential size hit by putting capacity/reserved in one
|
||||
* struct, then putting the array (if any) in a derived struct. If no array
|
||||
* is needed, the derived struct won't consume extra space.
|
||||
*/
|
||||
struct CapacityAndReserved
|
||||
{
|
||||
explicit CapacityAndReserved(size_t aCapacity, size_t aReserved)
|
||||
: mCapacity(aCapacity)
|
||||
#ifdef DEBUG
|
||||
, mReserved(aReserved)
|
||||
#endif
|
||||
{}
|
||||
CapacityAndReserved() = default;
|
||||
|
||||
/* Max number of elements storable in the vector without resizing. */
|
||||
size_t mCapacity;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Max elements of reserved or used space in this vector. */
|
||||
size_t mReserved;
|
||||
/* Max elements of reserved or used space in this vector. */
|
||||
size_t mReserved;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Memory used for inline storage. */
|
||||
AlignedStorage<kInlineBytes> mStorage;
|
||||
// Silence warnings about this struct possibly being padded dued to the
|
||||
// alignas() in it -- there's nothing we can do to avoid it.
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4324)
|
||||
#endif // _MSC_VER
|
||||
|
||||
template<size_t Capacity, size_t Dummy>
|
||||
struct CRAndStorage : CapacityAndReserved
|
||||
{
|
||||
explicit CRAndStorage(size_t aCapacity, size_t aReserved)
|
||||
: CapacityAndReserved(aCapacity, aReserved)
|
||||
{}
|
||||
CRAndStorage() = default;
|
||||
|
||||
alignas(T) unsigned char mBytes[Capacity * sizeof(T)];
|
||||
|
||||
// GCC fails due to -Werror=strict-aliasing if |mBytes| is directly cast to
|
||||
// T*. Indirecting through this function addresses the problem.
|
||||
void* data() { return mBytes; }
|
||||
|
||||
T* storage() { return static_cast<T*>(data()); }
|
||||
};
|
||||
|
||||
template<size_t Dummy>
|
||||
struct CRAndStorage<0, Dummy> : CapacityAndReserved
|
||||
{
|
||||
explicit CRAndStorage(size_t aCapacity, size_t aReserved)
|
||||
: CapacityAndReserved(aCapacity, aReserved)
|
||||
{}
|
||||
CRAndStorage() = default;
|
||||
|
||||
T* storage() { return nullptr; }
|
||||
};
|
||||
|
||||
CRAndStorage<kInlineCapacity, 0> mTail;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
#ifdef DEBUG
|
||||
friend class ReentrancyGuard;
|
||||
|
|
@ -364,7 +438,7 @@ class Vector final : private AllocPolicy
|
|||
|
||||
T* inlineStorage()
|
||||
{
|
||||
return static_cast<T*>(mStorage.addr());
|
||||
return mTail.storage();
|
||||
}
|
||||
|
||||
T* beginNoCheck() const
|
||||
|
|
@ -392,9 +466,9 @@ class Vector final : private AllocPolicy
|
|||
*/
|
||||
size_t reserved() const
|
||||
{
|
||||
MOZ_ASSERT(mLength <= mReserved);
|
||||
MOZ_ASSERT(mReserved <= mCapacity);
|
||||
return mReserved;
|
||||
MOZ_ASSERT(mLength <= mTail.mReserved);
|
||||
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||
return mTail.mReserved;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -427,7 +501,7 @@ public:
|
|||
|
||||
bool empty() const { return mLength == 0; }
|
||||
|
||||
size_t capacity() const { return mCapacity; }
|
||||
size_t capacity() const { return mTail.mCapacity; }
|
||||
|
||||
T* begin()
|
||||
{
|
||||
|
|
@ -754,10 +828,10 @@ private:
|
|||
/* This does the re-entrancy check plus several other sanity checks. */
|
||||
#define MOZ_REENTRANCY_GUARD_ET_AL \
|
||||
ReentrancyGuard g(*this); \
|
||||
MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == kInlineCapacity); \
|
||||
MOZ_ASSERT(reserved() <= mCapacity); \
|
||||
MOZ_ASSERT_IF(usingInlineStorage(), mTail.mCapacity == kInlineCapacity); \
|
||||
MOZ_ASSERT(reserved() <= mTail.mCapacity); \
|
||||
MOZ_ASSERT(mLength <= reserved()); \
|
||||
MOZ_ASSERT(mLength <= mCapacity)
|
||||
MOZ_ASSERT(mLength <= mTail.mCapacity)
|
||||
|
||||
/* Vector Implementation */
|
||||
|
||||
|
|
@ -766,13 +840,12 @@ MOZ_ALWAYS_INLINE
|
|||
Vector<T, N, AP>::Vector(AP aAP)
|
||||
: AP(aAP)
|
||||
, mLength(0)
|
||||
, mCapacity(kInlineCapacity)
|
||||
, mTail(kInlineCapacity, 0)
|
||||
#ifdef DEBUG
|
||||
, mReserved(0)
|
||||
, mEntered(false)
|
||||
#endif
|
||||
{
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mBegin = inlineStorage();
|
||||
}
|
||||
|
||||
/* Move constructor. */
|
||||
|
|
@ -785,14 +858,14 @@ Vector<T, N, AllocPolicy>::Vector(Vector&& aRhs)
|
|||
#endif
|
||||
{
|
||||
mLength = aRhs.mLength;
|
||||
mCapacity = aRhs.mCapacity;
|
||||
mTail.mCapacity = aRhs.mTail.mCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = aRhs.mReserved;
|
||||
mTail.mReserved = aRhs.mTail.mReserved;
|
||||
#endif
|
||||
|
||||
if (aRhs.usingInlineStorage()) {
|
||||
/* We can't move the buffer over in this case, so copy elements. */
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mBegin = inlineStorage();
|
||||
Impl::moveConstruct(mBegin, aRhs.beginNoCheck(), aRhs.endNoCheck());
|
||||
/*
|
||||
* Leave aRhs's mLength, mBegin, mCapacity, and mReserved as they are.
|
||||
|
|
@ -804,11 +877,11 @@ Vector<T, N, AllocPolicy>::Vector(Vector&& aRhs)
|
|||
* in-line storage.
|
||||
*/
|
||||
mBegin = aRhs.mBegin;
|
||||
aRhs.mBegin = static_cast<T*>(aRhs.mStorage.addr());
|
||||
aRhs.mCapacity = kInlineCapacity;
|
||||
aRhs.mBegin = aRhs.inlineStorage();
|
||||
aRhs.mTail.mCapacity = kInlineCapacity;
|
||||
aRhs.mLength = 0;
|
||||
#ifdef DEBUG
|
||||
aRhs.mReserved = 0;
|
||||
aRhs.mTail.mReserved = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -872,7 +945,7 @@ Vector<T, N, AP>::convertToHeapStorage(size_t aNewCap)
|
|||
/* Switch in heap buffer. */
|
||||
mBegin = newBuf;
|
||||
/* mLength is unchanged. */
|
||||
mCapacity = aNewCap;
|
||||
mTail.mCapacity = aNewCap;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -880,7 +953,7 @@ template<typename T, size_t N, class AP>
|
|||
MOZ_NEVER_INLINE bool
|
||||
Vector<T, N, AP>::growStorageBy(size_t aIncr)
|
||||
{
|
||||
MOZ_ASSERT(mLength + aIncr > mCapacity);
|
||||
MOZ_ASSERT(mLength + aIncr > mTail.mCapacity);
|
||||
|
||||
/*
|
||||
* When choosing a new capacity, its size should is as close to 2**N bytes
|
||||
|
|
@ -972,9 +1045,9 @@ Vector<T, N, AP>::initCapacity(size_t aRequest)
|
|||
return false;
|
||||
}
|
||||
mBegin = newbuf;
|
||||
mCapacity = aRequest;
|
||||
mTail.mCapacity = aRequest;
|
||||
#ifdef DEBUG
|
||||
mReserved = aRequest;
|
||||
mTail.mReserved = aRequest;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
@ -999,7 +1072,7 @@ Vector<T, N, AP>::maybeCheckSimulatedOOM(size_t aRequestedSize)
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (aRequestedSize <= mReserved) {
|
||||
if (aRequestedSize <= mTail.mReserved) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1012,7 +1085,7 @@ inline bool
|
|||
Vector<T, N, AP>::reserve(size_t aRequest)
|
||||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
if (aRequest > mCapacity) {
|
||||
if (aRequest > mTail.mCapacity) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(aRequest - mLength))) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1020,11 +1093,11 @@ Vector<T, N, AP>::reserve(size_t aRequest)
|
|||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (aRequest > mReserved) {
|
||||
mReserved = aRequest;
|
||||
if (aRequest > mTail.mReserved) {
|
||||
mTail.mReserved = aRequest;
|
||||
}
|
||||
MOZ_ASSERT(mLength <= mReserved);
|
||||
MOZ_ASSERT(mReserved <= mCapacity);
|
||||
MOZ_ASSERT(mLength <= mTail.mReserved);
|
||||
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1052,20 +1125,20 @@ MOZ_ALWAYS_INLINE bool
|
|||
Vector<T, N, AP>::growBy(size_t aIncr)
|
||||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
if (aIncr > mCapacity - mLength) {
|
||||
if (aIncr > mTail.mCapacity - mLength) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(aIncr))) {
|
||||
return false;
|
||||
}
|
||||
} else if (!maybeCheckSimulatedOOM(mLength + aIncr)) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(mLength + aIncr <= mCapacity);
|
||||
MOZ_ASSERT(mLength + aIncr <= mTail.mCapacity);
|
||||
T* newend = endNoCheck() + aIncr;
|
||||
Impl::initialize(endNoCheck(), newend);
|
||||
mLength += aIncr;
|
||||
#ifdef DEBUG
|
||||
if (mLength > mReserved) {
|
||||
mReserved = mLength;
|
||||
if (mLength > mTail.mReserved) {
|
||||
mTail.mReserved = mLength;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
|
|
@ -1076,7 +1149,7 @@ MOZ_ALWAYS_INLINE bool
|
|||
Vector<T, N, AP>::growByUninitialized(size_t aIncr)
|
||||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
if (aIncr > mCapacity - mLength) {
|
||||
if (aIncr > mTail.mCapacity - mLength) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(aIncr))) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1084,8 +1157,8 @@ Vector<T, N, AP>::growByUninitialized(size_t aIncr)
|
|||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (mLength + aIncr > mReserved) {
|
||||
mReserved = mLength + aIncr;
|
||||
if (mLength + aIncr > mTail.mReserved) {
|
||||
mTail.mReserved = mLength + aIncr;
|
||||
}
|
||||
#endif
|
||||
infallibleGrowByUninitialized(aIncr);
|
||||
|
|
@ -1143,10 +1216,10 @@ Vector<T, N, AP>::clearAndFree()
|
|||
return;
|
||||
}
|
||||
this->free_(beginNoCheck());
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mCapacity = kInlineCapacity;
|
||||
mBegin = inlineStorage();
|
||||
mTail.mCapacity = kInlineCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = 0;
|
||||
mTail.mReserved = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1163,7 +1236,7 @@ template<typename T, size_t N, class AP>
|
|||
inline bool
|
||||
Vector<T, N, AP>::canAppendWithoutRealloc(size_t aNeeded) const
|
||||
{
|
||||
return mLength + aNeeded <= mCapacity;
|
||||
return mLength + aNeeded <= mTail.mCapacity;
|
||||
}
|
||||
|
||||
template<typename T, size_t N, class AP>
|
||||
|
|
@ -1179,8 +1252,8 @@ template<typename U>
|
|||
MOZ_ALWAYS_INLINE void
|
||||
Vector<T, N, AP>::internalAppend(U&& aU)
|
||||
{
|
||||
MOZ_ASSERT(mLength + 1 <= mReserved);
|
||||
MOZ_ASSERT(mReserved <= mCapacity);
|
||||
MOZ_ASSERT(mLength + 1 <= mTail.mReserved);
|
||||
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||
Impl::new_(endNoCheck(), Forward<U>(aU));
|
||||
++mLength;
|
||||
}
|
||||
|
|
@ -1190,7 +1263,7 @@ MOZ_ALWAYS_INLINE bool
|
|||
Vector<T, N, AP>::appendN(const T& aT, size_t aNeeded)
|
||||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
if (mLength + aNeeded > mCapacity) {
|
||||
if (mLength + aNeeded > mTail.mCapacity) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1198,8 +1271,8 @@ Vector<T, N, AP>::appendN(const T& aT, size_t aNeeded)
|
|||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (mLength + aNeeded > mReserved) {
|
||||
mReserved = mLength + aNeeded;
|
||||
if (mLength + aNeeded > mTail.mReserved) {
|
||||
mTail.mReserved = mLength + aNeeded;
|
||||
}
|
||||
#endif
|
||||
internalAppendN(aT, aNeeded);
|
||||
|
|
@ -1210,8 +1283,8 @@ template<typename T, size_t N, class AP>
|
|||
MOZ_ALWAYS_INLINE void
|
||||
Vector<T, N, AP>::internalAppendN(const T& aT, size_t aNeeded)
|
||||
{
|
||||
MOZ_ASSERT(mLength + aNeeded <= mReserved);
|
||||
MOZ_ASSERT(mReserved <= mCapacity);
|
||||
MOZ_ASSERT(mLength + aNeeded <= mTail.mReserved);
|
||||
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||
Impl::copyConstructN(endNoCheck(), aNeeded, aT);
|
||||
mLength += aNeeded;
|
||||
}
|
||||
|
|
@ -1276,7 +1349,7 @@ Vector<T, N, AP>::append(const U* aInsBegin, const U* aInsEnd)
|
|||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
size_t aNeeded = PointerRangeSize(aInsBegin, aInsEnd);
|
||||
if (mLength + aNeeded > mCapacity) {
|
||||
if (mLength + aNeeded > mTail.mCapacity) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1284,8 +1357,8 @@ Vector<T, N, AP>::append(const U* aInsBegin, const U* aInsEnd)
|
|||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (mLength + aNeeded > mReserved) {
|
||||
mReserved = mLength + aNeeded;
|
||||
if (mLength + aNeeded > mTail.mReserved) {
|
||||
mTail.mReserved = mLength + aNeeded;
|
||||
}
|
||||
#endif
|
||||
internalAppend(aInsBegin, aNeeded);
|
||||
|
|
@ -1297,8 +1370,8 @@ template<typename U>
|
|||
MOZ_ALWAYS_INLINE void
|
||||
Vector<T, N, AP>::internalAppend(const U* aInsBegin, size_t aInsLength)
|
||||
{
|
||||
MOZ_ASSERT(mLength + aInsLength <= mReserved);
|
||||
MOZ_ASSERT(mReserved <= mCapacity);
|
||||
MOZ_ASSERT(mLength + aInsLength <= mTail.mReserved);
|
||||
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||
Impl::copyConstruct(endNoCheck(), aInsBegin, aInsBegin + aInsLength);
|
||||
mLength += aInsLength;
|
||||
}
|
||||
|
|
@ -1309,7 +1382,7 @@ MOZ_ALWAYS_INLINE bool
|
|||
Vector<T, N, AP>::append(U&& aU)
|
||||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
if (mLength == mCapacity) {
|
||||
if (mLength == mTail.mCapacity) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(1))) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1317,8 +1390,8 @@ Vector<T, N, AP>::append(U&& aU)
|
|||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (mLength + 1 > mReserved) {
|
||||
mReserved = mLength + 1;
|
||||
if (mLength + 1 > mTail.mReserved) {
|
||||
mTail.mReserved = mLength + 1;
|
||||
}
|
||||
#endif
|
||||
internalAppend(Forward<U>(aU));
|
||||
|
|
@ -1371,11 +1444,11 @@ Vector<T, N, AP>::extractRawBuffer()
|
|||
}
|
||||
|
||||
T* ret = mBegin;
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mBegin = inlineStorage();
|
||||
mLength = 0;
|
||||
mCapacity = kInlineCapacity;
|
||||
mTail.mCapacity = kInlineCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = 0;
|
||||
mTail.mReserved = 0;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1397,11 +1470,11 @@ Vector<T, N, AP>::extractOrCopyRawBuffer()
|
|||
|
||||
Impl::moveConstruct(copy, beginNoCheck(), endNoCheck());
|
||||
Impl::destroy(beginNoCheck(), endNoCheck());
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mBegin = inlineStorage();
|
||||
mLength = 0;
|
||||
mCapacity = kInlineCapacity;
|
||||
mTail.mCapacity = kInlineCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = 0;
|
||||
mTail.mReserved = 0;
|
||||
#endif
|
||||
return copy;
|
||||
}
|
||||
|
|
@ -1425,19 +1498,19 @@ Vector<T, N, AP>::replaceRawBuffer(T* aP, size_t aLength)
|
|||
* otherwise be acceptable. Maybe this behaviour should be
|
||||
* specifiable with an argument to this function.
|
||||
*/
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mBegin = inlineStorage();
|
||||
mLength = aLength;
|
||||
mCapacity = kInlineCapacity;
|
||||
mTail.mCapacity = kInlineCapacity;
|
||||
Impl::moveConstruct(mBegin, aP, aP + aLength);
|
||||
Impl::destroy(aP, aP + aLength);
|
||||
this->free_(aP);
|
||||
} else {
|
||||
mBegin = aP;
|
||||
mLength = aLength;
|
||||
mCapacity = aLength;
|
||||
mTail.mCapacity = aLength;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
mReserved = aLength;
|
||||
mTail.mReserved = aLength;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1476,9 +1549,9 @@ Vector<T, N, AP>::swap(Vector& aOther)
|
|||
}
|
||||
|
||||
Swap(mLength, aOther.mLength);
|
||||
Swap(mCapacity, aOther.mCapacity);
|
||||
Swap(mTail.mCapacity, aOther.mTail.mCapacity);
|
||||
#ifdef DEBUG
|
||||
Swap(mReserved, aOther.mReserved);
|
||||
Swap(mTail.mReserved, aOther.mTail.mReserved);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue