mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
946864fcd3
- Bug 1263188 - stop bleeding, r=yzen (e121b0dff3) - Bug 1263188 - more assertions, part3, r=yzen (6623350334) - Bug 1263188 - fix event tree coalescence, part4, r=yzen (dd4b0293ab) - Bug 1262417 - bind a value change event with reorder event firing, r=yzen (eee45f738e) - Bug 1287874: Add missing math.h include. r=drno (cd8b7e74d3) - Bug 967300 - enable cairo's atomic support on gcc-esque compilers; r=mshal (025d886e53) - Bug 1158871 - use new-style __atomic_* primitives in cairo; r=jrmuizel,ted.mielczarek (9ac76e7769) - fix build on non-windows systems (d807139c54) - Bug 1205854 - Workaround for Windows printer drivers that can't handle swapped X and Y axes. r=jrmuizel (1f35fc8d76) - Bug 1186339 - skip STUN/TURN servers with non-matching IP versions for TCP sockets. r=bwc (61f841554e) - Bug 933986. Switch over from index to an id, and ensure uniqueness when feeding into the candidate priority calculation. r=drno (168f4d68a3) - Bug 1190720 - only check IP version for STUN server IPs. r=bwc (9f95c5995f) - Bug 1192403 - improve ICE TCP error message. r=mjf (28afcf181c) - Bug 1037618 - Part 1: Add some logging to highlight TCP connection failures. r=drno (f5f861563a) - Bug 1251214: Ignore R_WOULDBLOCK in nr_stun_client_send_request r=ekr (00db6e3022) - Bug 980609: Do not assert that TURN TCP client contexts can't fail before attempting to allocate. r=ekr (3c20586954) - Bug 1237299: addedd missing address family to DNS lookup for proxies r=bwc (eea322d3e1) - Bug 1258753: Base candidate pair priority on controlling/controlled. r=drno (52dc0783ca) - Bug 1246363: add logging to detect if relay only option is set. r=mjf (fab0c5aec8) - Bug 1252777: skip over ICE TCP host candidate creation failures. r=bwc (2225289e5e) - Bug 1242324: Give VP9 priority over vp8 when both are enabled r=drno (5e31cde0b1) - Bug 1247656: Make sure that remote reoffer does not change the media type of an m-line. r=drno (d34bd649b3) - Bug 906986 - Ice restart and tests. r=bwc, r=drno, r=smaug (080ee96a4c) - Bug 1259842: allow RFC1918 pairing again r=mjf (ab11d2a41a) - Bug 1233181: improve misleading log message about missing STUN & TURN servers. r?=mjf (f744195587) - Bug 1244338 - Don't try to clean up |ctx| if null. r=drno (4c7da59d2e) - Bug 1256720: Remove a bad assertion, and simplify some code. r=drno (e8f5d04e93) - Bug 1257472: Forgive rport of 0. r=drno,ekr (8d02b24855) - Bug 1214279: Fix the same infinite loop from bug 957236 in a different place. r=drno (9780450268) - Bug 1229633: hash interface names on Windows. r=ekr (6ff60bf22a) - Bug 895793: added interface type and link speed detection for Windows. r=bwc (f7783adae6) - Bug 1180311 - Add null check to ifa_addr. r=ekr (90658f741b) - Bug 1183985: Fixed WebRTC socket leak on Linux. r=bwc (b06efe6ee9) - Bug 1231117 - Use xlocale on DragonFly as well. r=jesup (e7a09ee751) - Bug 1254780 (attempt 2) - Shrink log_types from 1024 entries to 16. r=ekr. (efa73ca5af) - Bug 1187075: Implement cairo atomics for Win32. r=jrmuizel (5b92bd3cff) - Bug 1161170 - backport upstream fix for race in Cairo freed_pool. r=jrmuizel (3287e5b154) - Bug 1255269. Get rid of nsITCPSocketCallback.fireDataEvent. r=jdm (9460469c15) - Bug 1246925 - log filtering_type and mapping_type only if they are valid pointers. r=ekr (57af98cd1f) - Bug 1248637: Prune duplicate CANCELLED candidate pairs. r=drno (c982b8492d) - Bug 676001 - Fix for stroke hit testing on cairo. r=jrmuizel (1cedebd554) - Bug 1252171: Update last_used_ on TCP port mappings when they are used, similar to UDP. r=drno (9229a3316a) - Bug 906986 - Rework rollback/finalize to include a committed state. r=bwc, r=drno (14ec947fd3) - Bug 1264344 - Don't restart ICE on first CreateOffer call if iceRestart option is true. r=bwc (d2850773f6) - Bug 1208371 - Update sink identity after adding track. r=mt (032aa5fcc4) - Bug 1247547: removed double accounting for WEBRTC_ICE_ADD_CANDIDATE telemetry probes. r=bwc (5abdc7d93a) - Bug 1254691 - Remove SEC_NORMAL from webrtc/. r=bwc (20dfff4efd) - Bug 1264351: removed hand break which disables ICE TCP on e10s r=jesup (6bc2a9936d) - bit of Bug 906986 - Rework rollback/finalize (ab1f5378f2) - Bug 1161619: RunStatsQuery leak fix. r=jib (2e4aca6869) - Bug 1256430: start AEC log independently of webrtc TRACE r=jesup,pkerr (29978d0a69) - Bug 1260784 - fix Stop Debug Mode button r=jesup (a1ac6fb833) - Bug 1220043 - Add workaround for internal complier error by VS2015. r=rjesup (c4368b1cad) - Bug 1252073 - Uninitialised value uses in mozilla::EncodingConstraints::operator==. r=docfaraday@gmail.com. (1be0174cd9) - Bug 1179859 - Fix _cairo_box_intersects_line_segment early rejection tests. r=jrmuizel (b2493a8c1e) - Bug 1186040 - use XPCOM refcounting macros instead of mozilla::RefCounted in WebrtcGlobalParent.h; r=jesup (f9bb1ba504) - Bug 1188407: switch packetloss to a rate from total-packets-lost-per-update r=jib (96297c4cd7) - Bug 1202696 - check surface status in _cairo_surface_get_extents. r=jmuizelaar (3f5c49d9d5) - Bug 1207750 - setting an environment variable will let us crash as Cairo errors happen. r=bschouten (caf8d9ee9a) - Bug 1215774 - use abort() to abort on error in Cairo. r=jmuizelaar (36e9c0bb2b) - minor (d2d4a96024) - Bug 1246011: fixed PT comparising for PT's without rtpmap. r=jesup (38c1f91a1f) - Bug 1249098: Support maxplaybackrate for opus. r=jesup (7a38717c47) - Bug 818618: Honor (and emit) opus stereo fmtp param. r=jesup (436175287f) - Bug 1258558 - Don't check extents for empty regions. r=jrmuizel (3751780ae0) - Bug 1236266 - Don't generate invalid empty regions in pixman (r=jmuielaar) (2c22835afd) - Bug 1255281. Add pixman fast path for bilinear x888_8888_SRC. r=lsalzman (0e585d5114) - Bug 1241012: Remove moz-d2d1-1.h stub headers from the tree. r=jrmuizel Please enter the commit message for your changes. Lines starting (b1dc61c08b) - Bug 1240790: Add newlines to WEBRTC_TRACE_FILE. r=rjesup (d25a696ff8) - bug 1241064 - updating stats filter SSRC when audio channel SSRC changes; r=jib (481c2ad1e0) - Bug 1247574: Force webrtc audio input processing to resample to target rate to fix 16KHz mics. r=padenot (9dea99341e) - Bug 1158741 - Implement a version of omxSP_FFTInv_CCSToR_F32_Sfs in openmax DL's FFT that is not scaled r=padenot (0acefaf93a) - Bug 1253149 - Use bool instead of int for boolean return values. r=SimonSapin (0303c4c8ab)
516 lines
15 KiB
C++
516 lines
15 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||
|
||
#include "EventTree.h"
|
||
|
||
#include "Accessible-inl.h"
|
||
#include "nsEventShell.h"
|
||
#include "DocAccessible.h"
|
||
#ifdef A11Y_LOG
|
||
#include "Logging.h"
|
||
#endif
|
||
|
||
using namespace mozilla;
|
||
using namespace mozilla::a11y;
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// TreeMutation class
|
||
|
||
EventTree* const TreeMutation::kNoEventTree = reinterpret_cast<EventTree*>(-1);
|
||
|
||
TreeMutation::TreeMutation(Accessible* aParent, bool aNoEvents) :
|
||
mParent(aParent), mStartIdx(UINT32_MAX),
|
||
mStateFlagsCopy(mParent->mStateFlags),
|
||
mEventTree(aNoEvents ? kNoEventTree : nullptr)
|
||
{
|
||
#ifdef DEBUG
|
||
mIsDone = false;
|
||
#endif
|
||
|
||
#ifdef A11Y_LOG
|
||
if (mEventTree != kNoEventTree && logging::IsEnabled(logging::eEventTree)) {
|
||
logging::MsgBegin("EVENTS_TREE", "reordering tree before");
|
||
logging::AccessibleInfo("reordering for", mParent);
|
||
Controller()->RootEventTree().Log();
|
||
logging::MsgEnd();
|
||
|
||
logging::MsgBegin("EVENTS_TREE", "Container tree");
|
||
if (logging::IsEnabled(logging::eVerbose)) {
|
||
nsAutoString level;
|
||
Accessible* root = mParent->Document();
|
||
do {
|
||
const char* prefix = "";
|
||
if (mParent == root) {
|
||
prefix = "_X_";
|
||
}
|
||
else {
|
||
const EventTree& ret = Controller()->RootEventTree();
|
||
if (ret.Find(root)) {
|
||
prefix = "_с_";
|
||
}
|
||
}
|
||
|
||
printf("%s", NS_ConvertUTF16toUTF8(level).get());
|
||
logging::AccessibleInfo(prefix, root);
|
||
if (root->FirstChild() && !root->FirstChild()->IsDoc()) {
|
||
level.Append(NS_LITERAL_STRING(" "));
|
||
root = root->FirstChild();
|
||
continue;
|
||
}
|
||
int32_t idxInParent = root->mParent ?
|
||
root->mParent->mChildren.IndexOf(root) : -1;
|
||
if (idxInParent != -1 &&
|
||
idxInParent < static_cast<int32_t>(root->mParent->mChildren.Length() - 1)) {
|
||
root = root->mParent->mChildren.ElementAt(idxInParent + 1);
|
||
continue;
|
||
}
|
||
|
||
while ((root = root->Parent()) && !root->IsDoc()) {
|
||
level.Cut(0, 2);
|
||
|
||
int32_t idxInParent = root->mParent ?
|
||
root->mParent->mChildren.IndexOf(root) : -1;
|
||
if (idxInParent != -1 &&
|
||
idxInParent < static_cast<int32_t>(root->mParent->mChildren.Length() - 1)) {
|
||
root = root->mParent->mChildren.ElementAt(idxInParent + 1);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
while (root && !root->IsDoc());
|
||
}
|
||
logging::MsgEnd();
|
||
}
|
||
#endif
|
||
|
||
mParent->mStateFlags |= Accessible::eKidsMutating;
|
||
}
|
||
|
||
TreeMutation::~TreeMutation()
|
||
{
|
||
MOZ_ASSERT(mIsDone, "Done() must be called explicitly");
|
||
}
|
||
|
||
void
|
||
TreeMutation::AfterInsertion(Accessible* aChild)
|
||
{
|
||
MOZ_ASSERT(aChild->Parent() == mParent);
|
||
|
||
if (static_cast<uint32_t>(aChild->mIndexInParent) < mStartIdx) {
|
||
mStartIdx = aChild->mIndexInParent + 1;
|
||
}
|
||
|
||
if (!mEventTree) {
|
||
mEventTree = Controller()->QueueMutation(mParent);
|
||
if (!mEventTree) {
|
||
mEventTree = kNoEventTree;
|
||
}
|
||
}
|
||
|
||
if (mEventTree != kNoEventTree) {
|
||
mEventTree->Shown(aChild);
|
||
Controller()->QueueNameChange(aChild);
|
||
}
|
||
}
|
||
|
||
void
|
||
TreeMutation::BeforeRemoval(Accessible* aChild, bool aNoShutdown)
|
||
{
|
||
MOZ_ASSERT(aChild->Parent() == mParent);
|
||
|
||
if (static_cast<uint32_t>(aChild->mIndexInParent) < mStartIdx) {
|
||
mStartIdx = aChild->mIndexInParent;
|
||
}
|
||
|
||
if (!mEventTree) {
|
||
mEventTree = Controller()->QueueMutation(mParent);
|
||
if (!mEventTree) {
|
||
mEventTree = kNoEventTree;
|
||
}
|
||
}
|
||
|
||
if (mEventTree != kNoEventTree) {
|
||
mEventTree->Hidden(aChild, !aNoShutdown);
|
||
Controller()->QueueNameChange(aChild);
|
||
}
|
||
}
|
||
|
||
void
|
||
TreeMutation::Done()
|
||
{
|
||
MOZ_ASSERT(mParent->mStateFlags & Accessible::eKidsMutating);
|
||
mParent->mStateFlags &= ~Accessible::eKidsMutating;
|
||
|
||
uint32_t length = mParent->mChildren.Length();
|
||
#ifdef DEBUG
|
||
for (uint32_t idx = 0; idx < mStartIdx && idx < length; idx++) {
|
||
MOZ_ASSERT(mParent->mChildren[idx]->mIndexInParent == static_cast<int32_t>(idx),
|
||
"Wrong index detected");
|
||
}
|
||
#endif
|
||
|
||
for (uint32_t idx = mStartIdx; idx < length; idx++) {
|
||
mParent->mChildren[idx]->mIndexInParent = idx;
|
||
mParent->mChildren[idx]->mStateFlags |= Accessible::eGroupInfoDirty;
|
||
}
|
||
|
||
if (mStartIdx < mParent->mChildren.Length() - 1) {
|
||
mParent->mEmbeddedObjCollector = nullptr;
|
||
}
|
||
|
||
mParent->mStateFlags |= mStateFlagsCopy & Accessible::eKidsMutating;
|
||
|
||
#ifdef DEBUG
|
||
mIsDone = true;
|
||
#endif
|
||
|
||
#ifdef A11Y_LOG
|
||
if (mEventTree != kNoEventTree && logging::IsEnabled(logging::eEventTree)) {
|
||
logging::MsgBegin("EVENTS_TREE", "reordering tree after");
|
||
logging::AccessibleInfo("reordering for", mParent);
|
||
Controller()->RootEventTree().Log();
|
||
logging::MsgEnd();
|
||
}
|
||
#endif
|
||
}
|
||
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// EventTree
|
||
|
||
void
|
||
EventTree::Process()
|
||
{
|
||
EventTree* node = mFirst;
|
||
while (node) {
|
||
// Skip a node and its subtree if its container is not in the document.
|
||
if (node->mContainer->IsInDocument()) {
|
||
node->Process();
|
||
}
|
||
node = node->mNext;
|
||
}
|
||
|
||
MOZ_ASSERT(mContainer || mDependentEvents.IsEmpty(),
|
||
"No container, no events");
|
||
MOZ_ASSERT(!mContainer || !mContainer->IsDefunct(),
|
||
"Processing events for defunct container");
|
||
|
||
// Fire mutation events.
|
||
uint32_t eventsCount = mDependentEvents.Length();
|
||
for (uint32_t jdx = 0; jdx < eventsCount; jdx++) {
|
||
AccMutationEvent* mtEvent = mDependentEvents[jdx];
|
||
MOZ_ASSERT(mtEvent->mEventRule != AccEvent::eDoNotEmit,
|
||
"The event shouldn't be presented in the tree");
|
||
|
||
nsEventShell::FireEvent(mtEvent);
|
||
if (mtEvent->mTextChangeEvent) {
|
||
nsEventShell::FireEvent(mtEvent->mTextChangeEvent);
|
||
}
|
||
|
||
if (mtEvent->IsHide()) {
|
||
// Fire menupopup end event before a hide event if a menu goes away.
|
||
|
||
// XXX: We don't look into children of hidden subtree to find hiding
|
||
// menupopup (as we did prior bug 570275) because we don't do that when
|
||
// menu is showing (and that's impossible until bug 606924 is fixed).
|
||
// Nevertheless we should do this at least because layout coalesces
|
||
// the changes before our processing and we may miss some menupopup
|
||
// events. Now we just want to be consistent in content insertion/removal
|
||
// handling.
|
||
if (mtEvent->mAccessible->ARIARole() == roles::MENUPOPUP) {
|
||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
|
||
mtEvent->mAccessible);
|
||
}
|
||
|
||
AccHideEvent* hideEvent = downcast_accEvent(mtEvent);
|
||
if (hideEvent->NeedsShutdown()) {
|
||
mtEvent->GetDocAccessible()->ShutdownChildrenInSubtree(mtEvent->mAccessible);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Fire reorder event at last.
|
||
if (mFireReorder) {
|
||
MOZ_ASSERT(mContainer);
|
||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_REORDER, mContainer);
|
||
mContainer->Document()->MaybeNotifyOfValueChange(mContainer);
|
||
}
|
||
|
||
mDependentEvents.Clear();
|
||
}
|
||
|
||
EventTree*
|
||
EventTree::FindOrInsert(Accessible* aContainer)
|
||
{
|
||
if (!mFirst) {
|
||
return mFirst = new EventTree(aContainer, true);
|
||
}
|
||
|
||
EventTree* prevNode = nullptr;
|
||
EventTree* node = mFirst;
|
||
do {
|
||
MOZ_ASSERT(!node->mContainer->IsApplication(),
|
||
"No event for application accessible is expected here");
|
||
MOZ_ASSERT(!node->mContainer->IsDefunct(), "An event target has to be alive");
|
||
|
||
// Case of same target.
|
||
if (node->mContainer == aContainer) {
|
||
return node;
|
||
}
|
||
|
||
// Check if the given container is contained by a current node
|
||
Accessible* top = mContainer ? mContainer : aContainer->Document();
|
||
Accessible* parent = aContainer;
|
||
while (parent) {
|
||
// Reached a top, no match for a current event.
|
||
if (parent == top) {
|
||
break;
|
||
}
|
||
|
||
// We got a match.
|
||
if (parent->Parent() == node->mContainer) {
|
||
return node->FindOrInsert(aContainer);
|
||
}
|
||
|
||
parent = parent->Parent();
|
||
MOZ_ASSERT(parent, "Wrong tree");
|
||
}
|
||
|
||
// If the given container contains a current node
|
||
// then
|
||
// if show or hide of the given node contains a grand parent of the current node
|
||
// then ignore the current node and its show and hide events
|
||
// otherwise ignore the current node, but not its show and hide events
|
||
Accessible* curParent = node->mContainer;
|
||
while (curParent && !curParent->IsDoc()) {
|
||
if (curParent->Parent() != aContainer) {
|
||
curParent = curParent->Parent();
|
||
continue;
|
||
}
|
||
|
||
// Insert the tail node into the hierarchy between the current node and
|
||
// its parent.
|
||
node->mFireReorder = false;
|
||
nsAutoPtr<EventTree>& nodeOwnerRef = prevNode ? prevNode->mNext : mFirst;
|
||
nsAutoPtr<EventTree> newNode(new EventTree(aContainer, mDependentEvents.IsEmpty()));
|
||
newNode->mFirst = Move(nodeOwnerRef);
|
||
nodeOwnerRef = Move(newNode);
|
||
nodeOwnerRef->mNext = Move(node->mNext);
|
||
|
||
// Check if a next node is contained by the given node too, and move them
|
||
// under the given node if so.
|
||
prevNode = nodeOwnerRef;
|
||
node = nodeOwnerRef->mNext;
|
||
nsAutoPtr<EventTree>* nodeRef = &nodeOwnerRef->mNext;
|
||
EventTree* insNode = nodeOwnerRef->mFirst;
|
||
while (node) {
|
||
Accessible* curParent = node->mContainer;
|
||
while (curParent && !curParent->IsDoc()) {
|
||
if (curParent->Parent() != aContainer) {
|
||
curParent = curParent->Parent();
|
||
continue;
|
||
}
|
||
|
||
MOZ_ASSERT(!insNode->mNext);
|
||
|
||
node->mFireReorder = false;
|
||
insNode->mNext = Move(*nodeRef);
|
||
insNode = insNode->mNext;
|
||
|
||
prevNode->mNext = Move(node->mNext);
|
||
node = prevNode;
|
||
break;
|
||
}
|
||
|
||
prevNode = node;
|
||
nodeRef = &node->mNext;
|
||
node = node->mNext;
|
||
}
|
||
|
||
return nodeOwnerRef;
|
||
}
|
||
|
||
prevNode = node;
|
||
} while ((node = node->mNext));
|
||
|
||
MOZ_ASSERT(prevNode, "Nowhere to insert");
|
||
MOZ_ASSERT(!prevNode->mNext, "Taken by another node");
|
||
|
||
// If 'this' node contains the given container accessible, then
|
||
// do not emit a reorder event for the container
|
||
// if a dependent show event target contains the given container then do not
|
||
// emit show / hide events (see Process() method)
|
||
|
||
return prevNode->mNext = new EventTree(aContainer, mDependentEvents.IsEmpty());
|
||
}
|
||
|
||
void
|
||
EventTree::Clear()
|
||
{
|
||
mFirst = nullptr;
|
||
mNext = nullptr;
|
||
mContainer = nullptr;
|
||
|
||
uint32_t eventsCount = mDependentEvents.Length();
|
||
for (uint32_t jdx = 0; jdx < eventsCount; jdx++) {
|
||
AccHideEvent* ev = downcast_accEvent(mDependentEvents[jdx]);
|
||
if (ev && ev->NeedsShutdown()) {
|
||
ev->GetDocAccessible()->ShutdownChildrenInSubtree(ev->mAccessible);
|
||
}
|
||
}
|
||
mDependentEvents.Clear();
|
||
}
|
||
|
||
const EventTree*
|
||
EventTree::Find(const Accessible* aContainer) const
|
||
{
|
||
const EventTree* et = this;
|
||
while (et) {
|
||
if (et->mContainer == aContainer) {
|
||
return et;
|
||
}
|
||
|
||
if (et->mFirst) {
|
||
et = et->mFirst;
|
||
const EventTree* cet = et->Find(aContainer);
|
||
if (cet) {
|
||
return cet;
|
||
}
|
||
}
|
||
|
||
et = et->mNext;
|
||
const EventTree* cet = et->Find(aContainer);
|
||
if (cet) {
|
||
return cet;
|
||
}
|
||
}
|
||
|
||
return nullptr;
|
||
}
|
||
|
||
#ifdef A11Y_LOG
|
||
void
|
||
EventTree::Log(uint32_t aLevel) const
|
||
{
|
||
if (aLevel == UINT32_MAX) {
|
||
if (mFirst) {
|
||
mFirst->Log(0);
|
||
}
|
||
return;
|
||
}
|
||
|
||
for (uint32_t i = 0; i < aLevel; i++) {
|
||
printf(" ");
|
||
}
|
||
logging::AccessibleInfo("container", mContainer);
|
||
|
||
for (uint32_t i = 0; i < mDependentEvents.Length(); i++) {
|
||
AccMutationEvent* ev = mDependentEvents[i];
|
||
if (ev->IsShow()) {
|
||
for (uint32_t i = 0; i < aLevel; i++) {
|
||
printf(" ");
|
||
}
|
||
logging::AccessibleInfo("shown", ev->mAccessible);
|
||
}
|
||
else {
|
||
for (uint32_t i = 0; i < aLevel; i++) {
|
||
printf(" ");
|
||
}
|
||
logging::AccessibleInfo("hidden", ev->mAccessible);
|
||
}
|
||
}
|
||
|
||
if (mFirst) {
|
||
mFirst->Log(aLevel + 1);
|
||
}
|
||
|
||
if (mNext) {
|
||
mNext->Log(aLevel);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
void
|
||
EventTree::Mutated(AccMutationEvent* aEv)
|
||
{
|
||
// If shown or hidden node is a root of previously mutated subtree, then
|
||
// discard those subtree mutations as we are no longer interested in them.
|
||
nsAutoPtr<EventTree>* node = &mFirst;
|
||
while (*node) {
|
||
if ((*node)->mContainer == aEv->mAccessible) {
|
||
*node = Move((*node)->mNext);
|
||
break;
|
||
}
|
||
node = &(*node)->mNext;
|
||
}
|
||
|
||
AccMutationEvent* prevEvent = mDependentEvents.SafeLastElement(nullptr);
|
||
mDependentEvents.AppendElement(aEv);
|
||
|
||
// Coalesce text change events from this hide/show event and the previous one.
|
||
if (prevEvent && aEv->mEventType == prevEvent->mEventType) {
|
||
if (aEv->IsHide()) {
|
||
// XXX: we need a way to ignore SplitNode and JoinNode() when they do not
|
||
// affect the text within the hypertext.
|
||
AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
|
||
if (prevTextEvent) {
|
||
AccHideEvent* hideEvent = downcast_accEvent(aEv);
|
||
AccHideEvent* prevHideEvent = downcast_accEvent(prevEvent);
|
||
|
||
if (prevHideEvent->mNextSibling == hideEvent->mAccessible) {
|
||
hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
|
||
}
|
||
else if (prevHideEvent->mPrevSibling == hideEvent->mAccessible) {
|
||
uint32_t oldLen = prevTextEvent->GetLength();
|
||
hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
|
||
prevTextEvent->mStart -= prevTextEvent->GetLength() - oldLen;
|
||
}
|
||
|
||
hideEvent->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
|
||
}
|
||
}
|
||
else {
|
||
AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
|
||
if (prevTextEvent) {
|
||
if (aEv->mAccessible->IndexInParent() ==
|
||
prevEvent->mAccessible->IndexInParent() + 1) {
|
||
// If tail target was inserted after this target, i.e. tail target is next
|
||
// sibling of this target.
|
||
aEv->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
|
||
}
|
||
else if (aEv->mAccessible->IndexInParent() ==
|
||
prevEvent->mAccessible->IndexInParent() - 1) {
|
||
// If tail target was inserted before this target, i.e. tail target is
|
||
// previous sibling of this target.
|
||
nsAutoString startText;
|
||
aEv->mAccessible->AppendTextTo(startText);
|
||
prevTextEvent->mModifiedText = startText + prevTextEvent->mModifiedText;
|
||
prevTextEvent->mStart -= startText.Length();
|
||
}
|
||
|
||
aEv->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Create a text change event caused by this hide/show event. When a node is
|
||
// hidden/removed or shown/appended, the text in an ancestor hyper text will
|
||
// lose or get new characters.
|
||
if (aEv->mTextChangeEvent || !mContainer->IsHyperText()) {
|
||
return;
|
||
}
|
||
|
||
nsAutoString text;
|
||
aEv->mAccessible->AppendTextTo(text);
|
||
if (text.IsEmpty()) {
|
||
return;
|
||
}
|
||
|
||
int32_t offset = mContainer->AsHyperText()->GetChildOffset(aEv->mAccessible);
|
||
aEv->mTextChangeEvent =
|
||
new AccTextChangeEvent(mContainer, offset, text, aEv->IsShow(),
|
||
aEv->mIsFromUserInput ? eFromUserInput : eNoUserInput);
|
||
}
|