merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2017-02-23 14:59:37 +01:00
commit e6b82618f4
164 changed files with 3229 additions and 60466 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -24,7 +24,7 @@
}
.accordion ._header:hover {
background-color: var(--theme-selection-color);
background-color: var(--theme-toolbar-hover);
}
.accordion ._header:hover svg {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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, &params, flags);
} else {
NS_ConvertUTF8toUTF16 str(nsDependentCString(test->string));
length = str.Length();
textRun = fontGroup->MakeTextRun(str.get(), length, &params, 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"

View file

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

View file

@ -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, &params, flags);
} else {
NS_ConvertUTF8toUTF16 str(nsDependentCString(test->mString));
length = str.Length();
textRun = fontGroup->MakeTextRun(str.get(), length, &params, 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));
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -657,6 +657,8 @@ description =
description =
[PPluginModule::InitCrashReporter]
description =
[PPluginModule::GetFileName]
description =
[PPluginScriptableObject::NPN_Evaluate]
description =
[PPluginScriptableObject::Invalidate]

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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">
(&#x1f602;&#x1f601;&#x1f600;)
</body>
</html>

View 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">
(&#x1f600;&#x1f601;&#x1f602;)
</body>
</html>

View 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">
&#x5d1;&#x1f600;&#x5d0;
</body>
</html>

View 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">
&#x5d0;&#x1f600;&#x5d1;
</body>
</html>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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