diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /accessible/windows/msaa/MsaaIdGenerator.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'accessible/windows/msaa/MsaaIdGenerator.cpp')
-rw-r--r-- | accessible/windows/msaa/MsaaIdGenerator.cpp | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/accessible/windows/msaa/MsaaIdGenerator.cpp b/accessible/windows/msaa/MsaaIdGenerator.cpp new file mode 100644 index 000000000..5f4b333fa --- /dev/null +++ b/accessible/windows/msaa/MsaaIdGenerator.cpp @@ -0,0 +1,243 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MsaaIdGenerator.h" + +#include "mozilla/a11y/AccessibleWrap.h" +#include "mozilla/ClearOnShutdown.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/Unused.h" +#include "nsDataHashtable.h" +#include "nsIXULRuntime.h" + +// These constants may be adjusted to modify the proportion of the Child ID +// allocated to the content ID vs proportion allocated to the unique ID. They +// must always sum to 31, ie. the width of a 32-bit integer less the sign bit. + +// NB: kNumContentProcessIDBits must be large enough to successfully hold the +// maximum permitted number of e10s content processes. If the e10s maximum +// number of content processes changes, then kNumContentProcessIDBits must also +// be updated if necessary to accommodate that new value! +static const uint32_t kNumContentProcessIDBits = 7UL; +static const uint32_t kNumUniqueIDBits = (31UL - kNumContentProcessIDBits); + +static_assert(kNumContentProcessIDBits + kNumUniqueIDBits == 31, + "Allocation of Content ID bits and Unique ID bits must sum to 31"); + +namespace mozilla { +namespace a11y { +namespace detail { + +typedef nsDataHashtable<nsUint64HashKey, uint32_t> ContentParentIdMap; + +#pragma pack(push, 1) +union MsaaID +{ + int32_t mInt32; + uint32_t mUInt32; + struct + { + uint32_t mUniqueID:kNumUniqueIDBits; + uint32_t mContentProcessID:kNumContentProcessIDBits; + uint32_t mSignBit:1; + } + mCracked; +}; +#pragma pack(pop) + +static uint32_t +BuildMsaaID(const uint32_t aID, const uint32_t aContentProcessID) +{ + MsaaID id; + id.mCracked.mSignBit = 0; + id.mCracked.mUniqueID = aID; + id.mCracked.mContentProcessID = aContentProcessID; + return ~id.mUInt32; +} + +class MsaaIDCracker +{ +public: + explicit MsaaIDCracker(const uint32_t aMsaaID) + { + mID.mUInt32 = ~aMsaaID; + } + + uint32_t GetContentProcessId() + { + return mID.mCracked.mContentProcessID; + } + + uint32_t GetUniqueId() + { + return mID.mCracked.mUniqueID; + } + +private: + MsaaID mID; +}; + +} // namespace detail + +constexpr MsaaIdGenerator::MsaaIdGenerator() + : mIDSet(kNumUniqueIDBits) +{} + +uint32_t +MsaaIdGenerator::GetID() +{ + uint32_t id = mIDSet.GetID(); + MOZ_ASSERT(id <= ((1UL << kNumUniqueIDBits) - 1UL)); + return detail::BuildMsaaID(id, ResolveContentProcessID()); +} + +void +MsaaIdGenerator::ReleaseID(AccessibleWrap* aAccWrap) +{ + MOZ_ASSERT(aAccWrap); + uint32_t id = aAccWrap->GetExistingID(); + MOZ_ASSERT(id != AccessibleWrap::kNoID); + detail::MsaaIDCracker cracked(id); + if (cracked.GetContentProcessId() != ResolveContentProcessID()) { + // This may happen if chrome holds a proxy whose ID was originally generated + // by a content process. Since ReleaseID only has meaning in the process + // that originally generated that ID, we ignore ReleaseID calls for any ID + // that did not come from the current process. + MOZ_ASSERT(aAccWrap->IsProxy()); + return; + } + mIDSet.ReleaseID(cracked.GetUniqueId()); +} + +bool +MsaaIdGenerator::IsChromeID(uint32_t aID) +{ + detail::MsaaIDCracker cracked(aID); + return cracked.GetContentProcessId() == 0; +} + +bool +MsaaIdGenerator::IsIDForThisContentProcess(uint32_t aID) +{ + MOZ_ASSERT(XRE_IsContentProcess()); + detail::MsaaIDCracker cracked(aID); + return cracked.GetContentProcessId() == ResolveContentProcessID(); +} + +bool +MsaaIdGenerator::IsIDForContentProcess(uint32_t aID, + dom::ContentParentId aIPCContentProcessId) +{ + MOZ_ASSERT(XRE_IsParentProcess()); + detail::MsaaIDCracker cracked(aID); + return cracked.GetContentProcessId() == + GetContentProcessIDFor(aIPCContentProcessId); +} + +bool +MsaaIdGenerator::IsSameContentProcessFor(uint32_t aFirstID, uint32_t aSecondID) +{ + detail::MsaaIDCracker firstCracked(aFirstID); + detail::MsaaIDCracker secondCracked(aSecondID); + return firstCracked.GetContentProcessId() == + secondCracked.GetContentProcessId(); +} + +uint32_t +MsaaIdGenerator::ResolveContentProcessID() +{ + if (XRE_IsParentProcess()) { + return 0; + } + + dom::ContentChild* contentChild = dom::ContentChild::GetSingleton(); + uint32_t result = contentChild->GetMsaaID(); + + MOZ_ASSERT(result); + return result; +} + +/** + * Each dom::ContentParent has a 64-bit ID. This ID is monotonically increasing + * with each new content process, so those IDs are effectively single-use. OTOH, + * MSAA requires 32-bit IDs. Since we only allocate kNumContentProcessIDBits for + * the content process ID component, the MSAA content process ID value must be + * reusable. sContentParentIdMap holds the current associations between + * dom::ContentParent IDs and the MSAA content parent IDs that have been + * allocated to them. + */ +static StaticAutoPtr<detail::ContentParentIdMap> sContentParentIdMap; + +static const uint32_t kBitsPerByte = 8UL; +// Set sContentProcessIdBitmap[0] to 1 to reserve the Chrome process's id +static uint64_t sContentProcessIdBitmap[(1UL << kNumContentProcessIDBits) / + (sizeof(uint64_t) * kBitsPerByte)] = {1ULL}; +static const uint32_t kBitsPerElement = sizeof(sContentProcessIdBitmap[0]) * + kBitsPerByte; + +uint32_t +MsaaIdGenerator::GetContentProcessIDFor(dom::ContentParentId aIPCContentProcessID) +{ + MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread()); + if (!sContentParentIdMap) { + sContentParentIdMap = new detail::ContentParentIdMap(); + ClearOnShutdown(&sContentParentIdMap); + } + + uint32_t value = 0; + if (sContentParentIdMap->Get(aIPCContentProcessID, &value)) { + return value; + } + + uint32_t index = 0; + for (; index < ArrayLength(sContentProcessIdBitmap); ++index) { + if (sContentProcessIdBitmap[index] == UINT64_MAX) { + continue; + } + uint32_t bitIndex = CountTrailingZeroes64(~sContentProcessIdBitmap[index]); + MOZ_ASSERT(!(sContentProcessIdBitmap[index] & (1ULL << bitIndex))); + MOZ_ASSERT(bitIndex != 0 || index != 0); + sContentProcessIdBitmap[index] |= (1ULL << bitIndex); + value = index * kBitsPerElement + bitIndex; + break; + } + + // If we run out of content process IDs, we're in trouble + MOZ_RELEASE_ASSERT(index < ArrayLength(sContentProcessIdBitmap)); + + sContentParentIdMap->Put(aIPCContentProcessID, value); + return value; +} + +void +MsaaIdGenerator::ReleaseContentProcessIDFor(dom::ContentParentId aIPCContentProcessID) +{ + MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread()); + if (!sContentParentIdMap) { + // Since Content IDs are generated lazily, ContentParent might attempt + // to release an ID that was never allocated to begin with. + return; + } + + Maybe<uint32_t> mapping = sContentParentIdMap->GetAndRemove(aIPCContentProcessID); + if (!mapping) { + // Since Content IDs are generated lazily, ContentParent might attempt + // to release an ID that was never allocated to begin with. + return; + } + + uint32_t index = mapping.ref() / kBitsPerElement; + MOZ_ASSERT(index < ArrayLength(sContentProcessIdBitmap)); + + uint64_t mask = 1ULL << (mapping.ref() % kBitsPerElement); + MOZ_ASSERT(sContentProcessIdBitmap[index] & mask); + + sContentProcessIdBitmap[index] &= ~mask; +} + +} // namespace a11y +} // namespace mozilla |