michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "OuterDocAccessible.h" michael@0: michael@0: #include "Accessible-inl.h" michael@0: #include "nsAccUtils.h" michael@0: #include "DocAccessible-inl.h" michael@0: #include "Role.h" michael@0: #include "States.h" michael@0: michael@0: #ifdef A11Y_LOG michael@0: #include "Logging.h" michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::a11y; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // OuterDocAccessible michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: OuterDocAccessible:: michael@0: OuterDocAccessible(nsIContent* aContent, DocAccessible* aDoc) : michael@0: AccessibleWrap(aContent, aDoc) michael@0: { michael@0: } michael@0: michael@0: OuterDocAccessible::~OuterDocAccessible() michael@0: { michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsISupports michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED0(OuterDocAccessible, michael@0: Accessible) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Accessible public (DON'T add methods here) michael@0: michael@0: role michael@0: OuterDocAccessible::NativeRole() michael@0: { michael@0: return roles::INTERNAL_FRAME; michael@0: } michael@0: michael@0: Accessible* michael@0: OuterDocAccessible::ChildAtPoint(int32_t aX, int32_t aY, michael@0: EWhichChildAtPoint aWhichChild) michael@0: { michael@0: int32_t docX = 0, docY = 0, docWidth = 0, docHeight = 0; michael@0: nsresult rv = GetBounds(&docX, &docY, &docWidth, &docHeight); michael@0: NS_ENSURE_SUCCESS(rv, nullptr); michael@0: michael@0: if (aX < docX || aX >= docX + docWidth || aY < docY || aY >= docY + docHeight) michael@0: return nullptr; michael@0: michael@0: // Always return the inner doc as direct child accessible unless bounds michael@0: // outside of it. michael@0: Accessible* child = GetChildAt(0); michael@0: NS_ENSURE_TRUE(child, nullptr); michael@0: michael@0: if (aWhichChild == eDeepestChild) michael@0: return child->ChildAtPoint(aX, aY, eDeepestChild); michael@0: return child; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIAccessible michael@0: michael@0: uint8_t michael@0: OuterDocAccessible::ActionCount() michael@0: { michael@0: // Internal frame, which is the doc's parent, should not have a click action. michael@0: return 0; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: OuterDocAccessible::GetActionName(uint8_t aIndex, nsAString& aName) michael@0: { michael@0: aName.Truncate(); michael@0: michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: OuterDocAccessible::GetActionDescription(uint8_t aIndex, michael@0: nsAString& aDescription) michael@0: { michael@0: aDescription.Truncate(); michael@0: michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: OuterDocAccessible::DoAction(uint8_t aIndex) michael@0: { michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Accessible public michael@0: michael@0: void michael@0: OuterDocAccessible::Shutdown() michael@0: { michael@0: // XXX: sometimes outerdoc accessible is shutdown because of layout style michael@0: // change however the presshell of underlying document isn't destroyed and michael@0: // the document doesn't get pagehide events. Schedule a document rebind michael@0: // to its parent document. Otherwise a document accessible may be lost if its michael@0: // outerdoc has being recreated (see bug 862863 for details). michael@0: michael@0: #ifdef A11Y_LOG michael@0: if (logging::IsEnabled(logging::eDocDestroy)) michael@0: logging::OuterDocDestroy(this); michael@0: #endif michael@0: michael@0: Accessible* child = mChildren.SafeElementAt(0, nullptr); michael@0: if (child) { michael@0: #ifdef A11Y_LOG michael@0: if (logging::IsEnabled(logging::eDocDestroy)) { michael@0: logging::DocDestroy("outerdoc's child document rebind is scheduled", michael@0: child->AsDoc()->DocumentNode()); michael@0: } michael@0: #endif michael@0: RemoveChild(child); michael@0: mDoc->BindChildDocument(child->AsDoc()); michael@0: } michael@0: michael@0: AccessibleWrap::Shutdown(); michael@0: } michael@0: michael@0: void michael@0: OuterDocAccessible::InvalidateChildren() michael@0: { michael@0: // Do not invalidate children because DocManager is responsible for michael@0: // document accessible lifetime when DOM document is created or destroyed. If michael@0: // DOM document isn't destroyed but its presshell is destroyed (for example, michael@0: // when DOM node of outerdoc accessible is hidden), then outerdoc accessible michael@0: // notifies DocManager about this. If presshell is created for existing michael@0: // DOM document (for example when DOM node of outerdoc accessible is shown) michael@0: // then allow DocManager to handle this case since the document michael@0: // accessible is created and appended as a child when it's requested. michael@0: michael@0: SetChildrenFlag(eChildrenUninitialized); michael@0: } michael@0: michael@0: bool michael@0: OuterDocAccessible::InsertChildAt(uint32_t aIdx, Accessible* aAccessible) michael@0: { michael@0: NS_ASSERTION(aAccessible->IsDoc(), michael@0: "OuterDocAccessible should only have document child!"); michael@0: // We keep showing the old document for a bit after creating the new one, michael@0: // and while building the new DOM and frame tree. That's done on purpose michael@0: // to avoid weird flashes of default background color. michael@0: // The old viewer will be destroyed after the new one is created. michael@0: // For a11y, it should be safe to shut down the old document now. michael@0: if (mChildren.Length()) michael@0: mChildren[0]->Shutdown(); michael@0: michael@0: if (!AccessibleWrap::InsertChildAt(0, aAccessible)) michael@0: return false; michael@0: michael@0: #ifdef A11Y_LOG michael@0: if (logging::IsEnabled(logging::eDocCreate)) { michael@0: logging::DocCreate("append document to outerdoc", michael@0: aAccessible->AsDoc()->DocumentNode()); michael@0: logging::Address("outerdoc", this); michael@0: } michael@0: #endif michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: OuterDocAccessible::RemoveChild(Accessible* aAccessible) michael@0: { michael@0: Accessible* child = mChildren.SafeElementAt(0, nullptr); michael@0: if (child != aAccessible) { michael@0: NS_ERROR("Wrong child to remove!"); michael@0: return false; michael@0: } michael@0: michael@0: #ifdef A11Y_LOG michael@0: if (logging::IsEnabled(logging::eDocDestroy)) { michael@0: logging::DocDestroy("remove document from outerdoc", michael@0: child->AsDoc()->DocumentNode(), child->AsDoc()); michael@0: logging::Address("outerdoc", this); michael@0: } michael@0: #endif michael@0: michael@0: bool wasRemoved = AccessibleWrap::RemoveChild(child); michael@0: michael@0: NS_ASSERTION(!mChildren.Length(), michael@0: "This child document of outerdoc accessible wasn't removed!"); michael@0: michael@0: return wasRemoved; michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Accessible protected michael@0: michael@0: void michael@0: OuterDocAccessible::CacheChildren() michael@0: { michael@0: // Request document accessible for the content document to make sure it's michael@0: // created. It will appended to outerdoc accessible children asynchronously. michael@0: nsIDocument* outerDoc = mContent->GetCurrentDoc(); michael@0: if (outerDoc) { michael@0: nsIDocument* innerDoc = outerDoc->GetSubDocumentFor(mContent); michael@0: if (innerDoc) michael@0: GetAccService()->GetDocAccessible(innerDoc); michael@0: } michael@0: }