blob: 3cca2dea3a7b940f7e77fc3f88cdaefda8567995 [file] [log] [blame]
/*
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "public/web/WebAXObject.h"
#include "SkMatrix44.h"
#include "core/HTMLNames.h"
#include "core/css/CSSPrimitiveValueMappings.h"
#include "core/dom/Document.h"
#include "core/dom/Node.h"
#include "core/editing/markers/DocumentMarker.h"
#include "core/frame/FrameHost.h"
#include "core/frame/FrameView.h"
#include "core/frame/VisualViewport.h"
#include "core/input/KeyboardEventManager.h"
#include "core/style/ComputedStyle.h"
#include "core/page/Page.h"
#include "modules/accessibility/AXObject.h"
#include "modules/accessibility/AXObjectCacheImpl.h"
#include "modules/accessibility/AXTable.h"
#include "modules/accessibility/AXTableCell.h"
#include "modules/accessibility/AXTableColumn.h"
#include "modules/accessibility/AXTableRow.h"
#include "public/platform/WebFloatRect.h"
#include "public/platform/WebPoint.h"
#include "public/platform/WebRect.h"
#include "public/platform/WebString.h"
#include "public/platform/WebURL.h"
#include "public/web/WebDocument.h"
#include "public/web/WebElement.h"
#include "public/web/WebNode.h"
#include "web/WebLocalFrameImpl.h"
#include "web/WebViewImpl.h"
#include "wtf/text/StringBuilder.h"
namespace blink {
#if DCHECK_IS_ON()
// It's not safe to call some WebAXObject APIs if a layout is pending.
// Clients should call updateLayoutAndCheckValidity first.
static bool isLayoutClean(Document* document) {
if (!document || !document->view())
return false;
return document->lifecycle().state() >= DocumentLifecycle::LayoutClean ||
((document->lifecycle().state() == DocumentLifecycle::StyleClean ||
document->lifecycle().state() ==
DocumentLifecycle::LayoutSubtreeChangeClean) &&
!document->view()->needsLayout());
}
#endif
WebScopedAXContext::WebScopedAXContext(WebDocument& rootDocument)
: m_private(ScopedAXObjectCache::create(*rootDocument.unwrap<Document>())) {
}
WebScopedAXContext::~WebScopedAXContext() {
m_private.reset(0);
}
WebAXObject WebScopedAXContext::root() const {
return WebAXObject(static_cast<AXObjectCacheImpl*>(m_private->get())->root());
}
void WebAXObject::reset() {
m_private.reset();
}
void WebAXObject::assign(const WebAXObject& other) {
m_private = other.m_private;
}
bool WebAXObject::equals(const WebAXObject& n) const {
return m_private.get() == n.m_private.get();
}
bool WebAXObject::isDetached() const {
if (m_private.isNull())
return true;
return m_private->isDetached();
}
int WebAXObject::axID() const {
if (isDetached())
return -1;
return m_private->axObjectID();
}
int WebAXObject::generateAXID() const {
if (isDetached())
return -1;
return m_private->axObjectCache().platformGenerateAXID();
}
bool WebAXObject::updateLayoutAndCheckValidity() {
if (!isDetached()) {
Document* document = m_private->getDocument();
if (!document || !document->view())
return false;
document->view()->updateLifecycleToCompositingCleanPlusScrolling();
}
// Doing a layout can cause this object to be invalid, so check again.
return !isDetached();
}
WebAXSupportedAction WebAXObject::action() const {
if (isDetached())
return WebAXSupportedAction::None;
return static_cast<WebAXSupportedAction>(m_private->action());
}
bool WebAXObject::canDecrement() const {
if (isDetached())
return false;
return m_private->isSlider();
}
bool WebAXObject::canIncrement() const {
if (isDetached())
return false;
return m_private->isSlider();
}
bool WebAXObject::canPress() const {
if (isDetached())
return false;
return m_private->actionElement() || m_private->isButton() ||
m_private->isMenuRelated();
}
bool WebAXObject::canSetFocusAttribute() const {
if (isDetached())
return false;
return m_private->canSetFocusAttribute();
}
bool WebAXObject::canSetValueAttribute() const {
if (isDetached())
return false;
return m_private->canSetValueAttribute();
}
unsigned WebAXObject::childCount() const {
if (isDetached())
return 0;
return m_private->children().size();
}
WebAXObject WebAXObject::childAt(unsigned index) const {
if (isDetached())
return WebAXObject();
if (m_private->children().size() <= index)
return WebAXObject();
return WebAXObject(m_private->children()[index]);
}
WebAXObject WebAXObject::parentObject() const {
if (isDetached())
return WebAXObject();
return WebAXObject(m_private->parentObject());
}
bool WebAXObject::canSetSelectedAttribute() const {
if (isDetached())
return false;
return m_private->canSetSelectedAttribute();
}
bool WebAXObject::isAnchor() const {
if (isDetached())
return false;
return m_private->isAnchor();
}
bool WebAXObject::isAriaReadOnly() const {
if (isDetached())
return false;
return equalIgnoringASCIICase(
m_private->getAttribute(HTMLNames::aria_readonlyAttr), "true");
}
WebString WebAXObject::ariaAutoComplete() const {
if (isDetached())
return WebString();
return m_private->ariaAutoComplete();
}
WebAXAriaCurrentState WebAXObject::ariaCurrentState() const {
if (isDetached())
return WebAXAriaCurrentStateUndefined;
return static_cast<WebAXAriaCurrentState>(m_private->ariaCurrentState());
}
bool WebAXObject::isButtonStateMixed() const {
if (isDetached())
return false;
return m_private->checkboxOrRadioValue() == ButtonStateMixed;
}
bool WebAXObject::isChecked() const {
if (isDetached())
return false;
return m_private->isChecked();
}
bool WebAXObject::isClickable() const {
if (isDetached())
return false;
return m_private->isClickable();
}
bool WebAXObject::isCollapsed() const {
if (isDetached())
return false;
return m_private->isCollapsed();
}
bool WebAXObject::isControl() const {
if (isDetached())
return false;
return m_private->isControl();
}
bool WebAXObject::isEnabled() const {
if (isDetached())
return false;
return m_private->isEnabled();
}
WebAXExpanded WebAXObject::isExpanded() const {
if (isDetached())
return WebAXExpandedUndefined;
return static_cast<WebAXExpanded>(m_private->isExpanded());
}
bool WebAXObject::isFocused() const {
if (isDetached())
return false;
return m_private->isFocused();
}
bool WebAXObject::isHovered() const {
if (isDetached())
return false;
return m_private->isHovered();
}
bool WebAXObject::isLinked() const {
if (isDetached())
return false;
return m_private->isLinked();
}
bool WebAXObject::isLoaded() const {
if (isDetached())
return false;
return m_private->isLoaded();
}
bool WebAXObject::isMultiSelectable() const {
if (isDetached())
return false;
return m_private->isMultiSelectable();
}
bool WebAXObject::isOffScreen() const {
if (isDetached())
return false;
return m_private->isOffScreen();
}
bool WebAXObject::isPasswordField() const {
if (isDetached())
return false;
return m_private->isPasswordField();
}
bool WebAXObject::isPressed() const {
if (isDetached())
return false;
return m_private->isPressed();
}
bool WebAXObject::isReadOnly() const {
if (isDetached())
return false;
return m_private->isReadOnly();
}
bool WebAXObject::isRequired() const {
if (isDetached())
return false;
return m_private->isRequired();
}
bool WebAXObject::isSelected() const {
if (isDetached())
return false;
return m_private->isSelected();
}
bool WebAXObject::isSelectedOptionActive() const {
if (isDetached())
return false;
return m_private->isSelectedOptionActive();
}
bool WebAXObject::isVisible() const {
if (isDetached())
return false;
return m_private->isVisible();
}
bool WebAXObject::isVisited() const {
if (isDetached())
return false;
return m_private->isVisited();
}
WebString WebAXObject::accessKey() const {
if (isDetached())
return WebString();
return WebString(m_private->accessKey());
}
unsigned WebAXObject::backgroundColor() const {
if (isDetached())
return 0;
// RGBA32 is an alias for unsigned int.
return m_private->backgroundColor();
}
unsigned WebAXObject::color() const {
if (isDetached())
return 0;
// RGBA32 is an alias for unsigned int.
return m_private->color();
}
// Deprecated.
void WebAXObject::colorValue(int& r, int& g, int& b) const {
if (isDetached())
return;
unsigned color = m_private->colorValue();
r = (color >> 16) & 0xFF;
g = (color >> 8) & 0xFF;
b = color & 0xFF;
}
unsigned WebAXObject::colorValue() const {
if (isDetached())
return 0;
// RGBA32 is an alias for unsigned int.
return m_private->colorValue();
}
WebAXObject WebAXObject::ariaActiveDescendant() const {
if (isDetached())
return WebAXObject();
return WebAXObject(m_private->activeDescendant());
}
bool WebAXObject::ariaControls(WebVector<WebAXObject>& controlsElements) const {
if (isDetached())
return false;
AXObject::AXObjectVector controls;
m_private->ariaControlsElements(controls);
WebVector<WebAXObject> result(controls.size());
for (size_t i = 0; i < controls.size(); i++)
result[i] = WebAXObject(controls[i]);
controlsElements.swap(result);
return true;
}
bool WebAXObject::ariaHasPopup() const {
if (isDetached())
return false;
return m_private->ariaHasPopup();
}
bool WebAXObject::ariaFlowTo(WebVector<WebAXObject>& flowToElements) const {
if (isDetached())
return false;
AXObject::AXObjectVector flowTo;
m_private->ariaFlowToElements(flowTo);
WebVector<WebAXObject> result(flowTo.size());
for (size_t i = 0; i < flowTo.size(); i++)
result[i] = WebAXObject(flowTo[i]);
flowToElements.swap(result);
return true;
}
bool WebAXObject::isEditable() const {
if (isDetached())
return false;
return m_private->isEditable();
}
bool WebAXObject::isMultiline() const {
if (isDetached())
return false;
return m_private->isMultiline();
}
bool WebAXObject::isRichlyEditable() const {
if (isDetached())
return false;
return m_private->isRichlyEditable();
}
int WebAXObject::posInSet() const {
if (isDetached())
return 0;
return m_private->posInSet();
}
int WebAXObject::setSize() const {
if (isDetached())
return 0;
return m_private->setSize();
}
bool WebAXObject::isInLiveRegion() const {
if (isDetached())
return false;
return 0 != m_private->liveRegionRoot();
}
bool WebAXObject::liveRegionAtomic() const {
if (isDetached())
return false;
return m_private->liveRegionAtomic();
}
bool WebAXObject::liveRegionBusy() const {
if (isDetached())
return false;
return m_private->liveRegionBusy();
}
WebString WebAXObject::liveRegionRelevant() const {
if (isDetached())
return WebString();
return m_private->liveRegionRelevant();
}
WebString WebAXObject::liveRegionStatus() const {
if (isDetached())
return WebString();
return m_private->liveRegionStatus();
}
WebAXObject WebAXObject::liveRegionRoot() const {
if (isDetached())
return WebAXObject();
AXObject* liveRegionRoot = m_private->liveRegionRoot();
if (liveRegionRoot)
return WebAXObject(liveRegionRoot);
return WebAXObject();
}
bool WebAXObject::containerLiveRegionAtomic() const {
if (isDetached())
return false;
return m_private->containerLiveRegionAtomic();
}
bool WebAXObject::containerLiveRegionBusy() const {
if (isDetached())
return false;
return m_private->containerLiveRegionBusy();
}
WebString WebAXObject::containerLiveRegionRelevant() const {
if (isDetached())
return WebString();
return m_private->containerLiveRegionRelevant();
}
WebString WebAXObject::containerLiveRegionStatus() const {
if (isDetached())
return WebString();
return m_private->containerLiveRegionStatus();
}
bool WebAXObject::ariaOwns(WebVector<WebAXObject>& ownsElements) const {
// aria-owns rearranges the accessibility tree rather than just
// exposing an attribute.
// FIXME(dmazzoni): remove this function after we stop calling it
// from Chromium. http://crbug.com/489590
return false;
}
WebString WebAXObject::fontFamily() const {
if (isDetached())
return WebString();
return m_private->fontFamily();
}
float WebAXObject::fontSize() const {
if (isDetached())
return 0.0f;
return m_private->fontSize();
}
bool WebAXObject::canvasHasFallbackContent() const {
if (isDetached())
return false;
return m_private->canvasHasFallbackContent();
}
WebString WebAXObject::imageDataUrl(const WebSize& maxSize) const {
if (isDetached())
return WebString();
return m_private->imageDataUrl(maxSize);
}
WebAXInvalidState WebAXObject::invalidState() const {
if (isDetached())
return WebAXInvalidStateUndefined;
return static_cast<WebAXInvalidState>(m_private->getInvalidState());
}
// Only used when invalidState() returns WebAXInvalidStateOther.
WebString WebAXObject::ariaInvalidValue() const {
if (isDetached())
return WebString();
return m_private->ariaInvalidValue();
}
double WebAXObject::estimatedLoadingProgress() const {
if (isDetached())
return 0.0;
return m_private->estimatedLoadingProgress();
}
int WebAXObject::headingLevel() const {
if (isDetached())
return 0;
return m_private->headingLevel();
}
int WebAXObject::hierarchicalLevel() const {
if (isDetached())
return 0;
return m_private->hierarchicalLevel();
}
// FIXME: This method passes in a point that has page scale applied but assumes
// that (0, 0) is the top left of the visual viewport. In other words, the
// point has the VisualViewport scale applied, but not the VisualViewport
// offset. crbug.com/459591.
WebAXObject WebAXObject::hitTest(const WebPoint& point) const {
if (isDetached())
return WebAXObject();
IntPoint contentsPoint =
m_private->documentFrameView()->soonToBeRemovedUnscaledViewportToContents(
point);
AXObject* hit = m_private->accessibilityHitTest(contentsPoint);
if (hit)
return WebAXObject(hit);
if (m_private->getBoundsInFrameCoordinates().contains(contentsPoint))
return *this;
return WebAXObject();
}
WebString WebAXObject::keyboardShortcut() const {
if (isDetached())
return WebString();
String accessKey = m_private->accessKey();
if (accessKey.isNull())
return WebString();
DEFINE_STATIC_LOCAL(String, modifierString, ());
if (modifierString.isNull()) {
unsigned modifiers = KeyboardEventManager::kAccessKeyModifiers;
// Follow the same order as Mozilla MSAA implementation:
// Ctrl+Alt+Shift+Meta+key. MSDN states that keyboard shortcut strings
// should not be localized and defines the separator as "+".
StringBuilder modifierStringBuilder;
if (modifiers & WebInputEvent::ControlKey)
modifierStringBuilder.append("Ctrl+");
if (modifiers & WebInputEvent::AltKey)
modifierStringBuilder.append("Alt+");
if (modifiers & WebInputEvent::ShiftKey)
modifierStringBuilder.append("Shift+");
if (modifiers & WebInputEvent::MetaKey)
modifierStringBuilder.append("Win+");
modifierString = modifierStringBuilder.toString();
}
return String(modifierString + accessKey);
}
WebString WebAXObject::language() const {
if (isDetached())
return WebString();
return m_private->language();
}
bool WebAXObject::performDefaultAction() const {
if (isDetached())
return false;
return m_private->performDefaultAction();
}
bool WebAXObject::increment() const {
if (isDetached())
return false;
if (canIncrement()) {
m_private->increment();
return true;
}
return false;
}
bool WebAXObject::decrement() const {
if (isDetached())
return false;
if (canDecrement()) {
m_private->decrement();
return true;
}
return false;
}
WebAXOrientation WebAXObject::orientation() const {
if (isDetached())
return WebAXOrientationUndefined;
return static_cast<WebAXOrientation>(m_private->orientation());
}
bool WebAXObject::press() const {
if (isDetached())
return false;
return m_private->press();
}
WebAXRole WebAXObject::role() const {
if (isDetached())
return WebAXRoleUnknown;
return static_cast<WebAXRole>(m_private->roleValue());
}
void WebAXObject::selection(WebAXObject& anchorObject,
int& anchorOffset,
WebAXTextAffinity& anchorAffinity,
WebAXObject& focusObject,
int& focusOffset,
WebAXTextAffinity& focusAffinity) const {
if (isDetached()) {
anchorObject = WebAXObject();
anchorOffset = -1;
anchorAffinity = WebAXTextAffinityDownstream;
focusObject = WebAXObject();
focusOffset = -1;
focusAffinity = WebAXTextAffinityDownstream;
return;
}
AXObject::AXRange axSelection = m_private->selection();
anchorObject = WebAXObject(axSelection.anchorObject);
anchorOffset = axSelection.anchorOffset;
anchorAffinity = static_cast<WebAXTextAffinity>(axSelection.anchorAffinity);
focusObject = WebAXObject(axSelection.focusObject);
focusOffset = axSelection.focusOffset;
focusAffinity = static_cast<WebAXTextAffinity>(axSelection.focusAffinity);
return;
}
void WebAXObject::setSelection(const WebAXObject& anchorObject,
int anchorOffset,
const WebAXObject& focusObject,
int focusOffset) const {
if (isDetached())
return;
AXObject::AXRange axSelection(anchorObject, anchorOffset,
TextAffinity::Upstream, focusObject,
focusOffset, TextAffinity::Downstream);
m_private->setSelection(axSelection);
return;
}
unsigned WebAXObject::selectionEnd() const {
if (isDetached())
return 0;
AXObject::AXRange axSelection = m_private->selectionUnderObject();
if (axSelection.focusOffset < 0)
return 0;
return axSelection.focusOffset;
}
unsigned WebAXObject::selectionStart() const {
if (isDetached())
return 0;
AXObject::AXRange axSelection = m_private->selectionUnderObject();
if (axSelection.anchorOffset < 0)
return 0;
return axSelection.anchorOffset;
}
unsigned WebAXObject::selectionEndLineNumber() const {
if (isDetached())
return 0;
VisiblePosition position = m_private->visiblePositionForIndex(selectionEnd());
int lineNumber = m_private->lineForPosition(position);
if (lineNumber < 0)
return 0;
return lineNumber;
}
unsigned WebAXObject::selectionStartLineNumber() const {
if (isDetached())
return 0;
VisiblePosition position =
m_private->visiblePositionForIndex(selectionStart());
int lineNumber = m_private->lineForPosition(position);
if (lineNumber < 0)
return 0;
return lineNumber;
}
void WebAXObject::setFocused(bool on) const {
if (!isDetached())
m_private->setFocused(on);
}
void WebAXObject::setSelectedTextRange(int selectionStart,
int selectionEnd) const {
if (isDetached())
return;
m_private->setSelection(AXObject::AXRange(selectionStart, selectionEnd));
}
void WebAXObject::setSequentialFocusNavigationStartingPoint() const {
if (isDetached())
return;
m_private->setSequentialFocusNavigationStartingPoint();
}
void WebAXObject::setValue(WebString value) const {
if (isDetached())
return;
m_private->setValue(value);
}
void WebAXObject::showContextMenu() const {
if (isDetached())
return;
Node* node = m_private->getNode();
if (!node)
return;
Element* element = nullptr;
if (node->isElementNode()) {
element = toElement(node);
} else if (node->isDocumentNode()) {
element = node->document().documentElement();
} else {
node->updateDistribution();
ContainerNode* parent = FlatTreeTraversal::parent(*node);
if (!parent)
return;
SECURITY_DCHECK(parent->isElementNode());
element = toElement(parent);
}
if (!element)
return;
LocalFrame* frame = element->document().frame();
if (!frame)
return;
WebViewImpl* view = WebLocalFrameImpl::fromFrame(frame)->viewImpl();
if (!view)
return;
view->showContextMenuForElement(WebElement(element));
}
WebString WebAXObject::stringValue() const {
if (isDetached())
return WebString();
return m_private->stringValue();
}
WebAXTextDirection WebAXObject::textDirection() const {
if (isDetached())
return WebAXTextDirectionLR;
return static_cast<WebAXTextDirection>(m_private->textDirection());
}
WebAXTextStyle WebAXObject::textStyle() const {
if (isDetached())
return WebAXTextStyleNone;
return static_cast<WebAXTextStyle>(m_private->getTextStyle());
}
WebURL WebAXObject::url() const {
if (isDetached())
return WebURL();
return m_private->url();
}
WebString WebAXObject::name(WebAXNameFrom& outNameFrom,
WebVector<WebAXObject>& outNameObjects) const {
if (isDetached())
return WebString();
AXNameFrom nameFrom = AXNameFromUninitialized;
HeapVector<Member<AXObject>> nameObjects;
WebString result = m_private->name(nameFrom, &nameObjects);
outNameFrom = static_cast<WebAXNameFrom>(nameFrom);
WebVector<WebAXObject> webNameObjects(nameObjects.size());
for (size_t i = 0; i < nameObjects.size(); i++)
webNameObjects[i] = WebAXObject(nameObjects[i]);
outNameObjects.swap(webNameObjects);
return result;
}
WebString WebAXObject::name() const {
if (isDetached())
return WebString();
AXNameFrom nameFrom;
HeapVector<Member<AXObject>> nameObjects;
return m_private->name(nameFrom, &nameObjects);
}
WebString WebAXObject::description(
WebAXNameFrom nameFrom,
WebAXDescriptionFrom& outDescriptionFrom,
WebVector<WebAXObject>& outDescriptionObjects) const {
if (isDetached())
return WebString();
AXDescriptionFrom descriptionFrom = AXDescriptionFromUninitialized;
HeapVector<Member<AXObject>> descriptionObjects;
String result = m_private->description(static_cast<AXNameFrom>(nameFrom),
descriptionFrom, &descriptionObjects);
outDescriptionFrom = static_cast<WebAXDescriptionFrom>(descriptionFrom);
WebVector<WebAXObject> webDescriptionObjects(descriptionObjects.size());
for (size_t i = 0; i < descriptionObjects.size(); i++)
webDescriptionObjects[i] = WebAXObject(descriptionObjects[i]);
outDescriptionObjects.swap(webDescriptionObjects);
return result;
}
WebString WebAXObject::placeholder(WebAXNameFrom nameFrom) const {
if (isDetached())
return WebString();
return m_private->placeholder(static_cast<AXNameFrom>(nameFrom));
}
bool WebAXObject::supportsRangeValue() const {
if (isDetached())
return false;
return m_private->supportsRangeValue();
}
WebString WebAXObject::valueDescription() const {
if (isDetached())
return WebString();
return m_private->valueDescription();
}
float WebAXObject::valueForRange() const {
if (isDetached())
return 0.0;
return m_private->valueForRange();
}
float WebAXObject::maxValueForRange() const {
if (isDetached())
return 0.0;
return m_private->maxValueForRange();
}
float WebAXObject::minValueForRange() const {
if (isDetached())
return 0.0;
return m_private->minValueForRange();
}
WebNode WebAXObject::node() const {
if (isDetached())
return WebNode();
Node* node = m_private->getNode();
if (!node)
return WebNode();
return WebNode(node);
}
WebDocument WebAXObject::document() const {
if (isDetached())
return WebDocument();
Document* document = m_private->getDocument();
if (!document)
return WebDocument();
return WebDocument(document);
}
bool WebAXObject::hasComputedStyle() const {
if (isDetached())
return false;
Document* document = m_private->getDocument();
if (document)
document->updateStyleAndLayoutTree();
Node* node = m_private->getNode();
if (!node)
return false;
return node->ensureComputedStyle();
}
WebString WebAXObject::computedStyleDisplay() const {
if (isDetached())
return WebString();
Document* document = m_private->getDocument();
if (document)
document->updateStyleAndLayoutTree();
Node* node = m_private->getNode();
if (!node)
return WebString();
const ComputedStyle* computedStyle = node->ensureComputedStyle();
if (!computedStyle)
return WebString();
return WebString(
CSSIdentifierValue::create(computedStyle->display())->cssText());
}
bool WebAXObject::accessibilityIsIgnored() const {
if (isDetached())
return false;
return m_private->accessibilityIsIgnored();
}
bool WebAXObject::lineBreaks(WebVector<int>& result) const {
if (isDetached())
return false;
Vector<int> lineBreaksVector;
m_private->lineBreaks(lineBreaksVector);
size_t vectorSize = lineBreaksVector.size();
WebVector<int> lineBreaksWebVector(vectorSize);
for (size_t i = 0; i < vectorSize; i++)
lineBreaksWebVector[i] = lineBreaksVector[i];
result.swap(lineBreaksWebVector);
return true;
}
int WebAXObject::ariaColumnCount() const {
if (isDetached())
return 0;
if (!m_private->isAXTable())
return 0;
return toAXTable(m_private.get())->ariaColumnCount();
}
unsigned WebAXObject::ariaColumnIndex() const {
if (isDetached())
return 0;
if (!m_private->isTableCell())
return 0;
return toAXTableCell(m_private.get())->ariaColumnIndex();
}
int WebAXObject::ariaRowCount() const {
if (isDetached())
return 0;
if (!m_private->isAXTable())
return 0;
return toAXTable(m_private.get())->ariaRowCount();
}
unsigned WebAXObject::ariaRowIndex() const {
if (isDetached())
return 0;
if (m_private->isTableCell())
return toAXTableCell(m_private.get())->ariaRowIndex();
if (m_private->isTableRow())
return toAXTableRow(m_private.get())->ariaRowIndex();
return 0;
}
unsigned WebAXObject::columnCount() const {
if (isDetached())
return false;
if (!m_private->isAXTable())
return 0;
return toAXTable(m_private.get())->columnCount();
}
unsigned WebAXObject::rowCount() const {
if (isDetached())
return 0;
if (!m_private->isAXTable())
return 0;
return toAXTable(m_private.get())->rowCount();
}
WebAXObject WebAXObject::cellForColumnAndRow(unsigned column,
unsigned row) const {
if (isDetached())
return WebAXObject();
if (!m_private->isAXTable())
return WebAXObject();
AXTableCell* cell =
toAXTable(m_private.get())->cellForColumnAndRow(column, row);
return WebAXObject(static_cast<AXObject*>(cell));
}
WebAXObject WebAXObject::headerContainerObject() const {
if (isDetached())
return WebAXObject();
if (!m_private->isAXTable())
return WebAXObject();
return WebAXObject(toAXTable(m_private.get())->headerContainer());
}
WebAXObject WebAXObject::rowAtIndex(unsigned rowIndex) const {
if (isDetached())
return WebAXObject();
if (!m_private->isAXTable())
return WebAXObject();
const AXObject::AXObjectVector& rows = toAXTable(m_private.get())->rows();
if (rowIndex < rows.size())
return WebAXObject(rows[rowIndex]);
return WebAXObject();
}
WebAXObject WebAXObject::columnAtIndex(unsigned columnIndex) const {
if (isDetached())
return WebAXObject();
if (!m_private->isAXTable())
return WebAXObject();
const AXObject::AXObjectVector& columns =
toAXTable(m_private.get())->columns();
if (columnIndex < columns.size())
return WebAXObject(columns[columnIndex]);
return WebAXObject();
}
unsigned WebAXObject::rowIndex() const {
if (isDetached())
return 0;
if (!m_private->isTableRow())
return 0;
return toAXTableRow(m_private.get())->rowIndex();
}
WebAXObject WebAXObject::rowHeader() const {
if (isDetached())
return WebAXObject();
if (!m_private->isTableRow())
return WebAXObject();
return WebAXObject(toAXTableRow(m_private.get())->headerObject());
}
void WebAXObject::rowHeaders(WebVector<WebAXObject>& rowHeaderElements) const {
if (isDetached())
return;
if (!m_private->isAXTable())
return;
AXObject::AXObjectVector headers;
toAXTable(m_private.get())->rowHeaders(headers);
size_t headerCount = headers.size();
WebVector<WebAXObject> result(headerCount);
for (size_t i = 0; i < headerCount; i++)
result[i] = WebAXObject(headers[i]);
rowHeaderElements.swap(result);
}
unsigned WebAXObject::columnIndex() const {
if (isDetached())
return 0;
if (m_private->roleValue() != ColumnRole)
return 0;
return toAXTableColumn(m_private.get())->columnIndex();
}
WebAXObject WebAXObject::columnHeader() const {
if (isDetached())
return WebAXObject();
if (m_private->roleValue() != ColumnRole)
return WebAXObject();
return WebAXObject(toAXTableColumn(m_private.get())->headerObject());
}
void WebAXObject::columnHeaders(
WebVector<WebAXObject>& columnHeaderElements) const {
if (isDetached())
return;
if (!m_private->isAXTable())
return;
AXObject::AXObjectVector headers;
toAXTable(m_private.get())->columnHeaders(headers);
size_t headerCount = headers.size();
WebVector<WebAXObject> result(headerCount);
for (size_t i = 0; i < headerCount; i++)
result[i] = WebAXObject(headers[i]);
columnHeaderElements.swap(result);
}
unsigned WebAXObject::cellColumnIndex() const {
if (isDetached())
return 0;
if (!m_private->isTableCell())
return 0;
std::pair<unsigned, unsigned> columnRange;
toAXTableCell(m_private.get())->columnIndexRange(columnRange);
return columnRange.first;
}
unsigned WebAXObject::cellColumnSpan() const {
if (isDetached())
return 0;
if (!m_private->isTableCell())
return 0;
std::pair<unsigned, unsigned> columnRange;
toAXTableCell(m_private.get())->columnIndexRange(columnRange);
return columnRange.second;
}
unsigned WebAXObject::cellRowIndex() const {
if (isDetached())
return 0;
if (!m_private->isTableCell())
return 0;
std::pair<unsigned, unsigned> rowRange;
toAXTableCell(m_private.get())->rowIndexRange(rowRange);
return rowRange.first;
}
unsigned WebAXObject::cellRowSpan() const {
if (isDetached())
return 0;
if (!m_private->isTableCell())
return 0;
std::pair<unsigned, unsigned> rowRange;
toAXTableCell(m_private.get())->rowIndexRange(rowRange);
return rowRange.second;
}
WebAXSortDirection WebAXObject::sortDirection() const {
if (isDetached())
return WebAXSortDirectionUndefined;
return static_cast<WebAXSortDirection>(m_private->getSortDirection());
}
void WebAXObject::loadInlineTextBoxes() const {
if (isDetached())
return;
m_private->loadInlineTextBoxes();
}
WebAXObject WebAXObject::nextOnLine() const {
if (isDetached())
return WebAXObject();
return WebAXObject(m_private.get()->nextOnLine());
}
WebAXObject WebAXObject::previousOnLine() const {
if (isDetached())
return WebAXObject();
return WebAXObject(m_private.get()->previousOnLine());
}
void WebAXObject::markers(WebVector<WebAXMarkerType>& types,
WebVector<int>& starts,
WebVector<int>& ends) const {
if (isDetached())
return;
Vector<DocumentMarker::MarkerType> markerTypes;
Vector<AXObject::AXRange> markerRanges;
m_private->markers(markerTypes, markerRanges);
DCHECK_EQ(markerTypes.size(), markerRanges.size());
WebVector<WebAXMarkerType> webMarkerTypes(markerTypes.size());
WebVector<int> startOffsets(markerRanges.size());
WebVector<int> endOffsets(markerRanges.size());
for (size_t i = 0; i < markerTypes.size(); ++i) {
webMarkerTypes[i] = static_cast<WebAXMarkerType>(markerTypes[i]);
DCHECK(markerRanges[i].isSimple());
startOffsets[i] = markerRanges[i].anchorOffset;
endOffsets[i] = markerRanges[i].focusOffset;
}
types.swap(webMarkerTypes);
starts.swap(startOffsets);
ends.swap(endOffsets);
}
void WebAXObject::characterOffsets(WebVector<int>& offsets) const {
if (isDetached())
return;
Vector<int> offsetsVector;
m_private->textCharacterOffsets(offsetsVector);
size_t vectorSize = offsetsVector.size();
WebVector<int> offsetsWebVector(vectorSize);
for (size_t i = 0; i < vectorSize; i++)
offsetsWebVector[i] = offsetsVector[i];
offsets.swap(offsetsWebVector);
}
void WebAXObject::wordBoundaries(WebVector<int>& starts,
WebVector<int>& ends) const {
if (isDetached())
return;
Vector<AXObject::AXRange> wordBoundaries;
m_private->wordBoundaries(wordBoundaries);
WebVector<int> wordStartOffsets(wordBoundaries.size());
WebVector<int> wordEndOffsets(wordBoundaries.size());
for (size_t i = 0; i < wordBoundaries.size(); ++i) {
DCHECK(wordBoundaries[i].isSimple());
wordStartOffsets[i] = wordBoundaries[i].anchorOffset;
wordEndOffsets[i] = wordBoundaries[i].focusOffset;
}
starts.swap(wordStartOffsets);
ends.swap(wordEndOffsets);
}
bool WebAXObject::isScrollableContainer() const {
if (isDetached())
return false;
return m_private->isScrollableContainer();
}
WebPoint WebAXObject::getScrollOffset() const {
if (isDetached())
return WebPoint();
return m_private->getScrollOffset();
}
WebPoint WebAXObject::minimumScrollOffset() const {
if (isDetached())
return WebPoint();
return m_private->minimumScrollOffset();
}
WebPoint WebAXObject::maximumScrollOffset() const {
if (isDetached())
return WebPoint();
return m_private->maximumScrollOffset();
}
void WebAXObject::setScrollOffset(const WebPoint& offset) const {
if (isDetached())
return;
m_private->setScrollOffset(offset);
}
void WebAXObject::getRelativeBounds(WebAXObject& offsetContainer,
WebFloatRect& boundsInContainer,
SkMatrix44& containerTransform) const {
if (isDetached())
return;
#if DCHECK_IS_ON()
DCHECK(isLayoutClean(m_private->getDocument()));
#endif
AXObject* container = nullptr;
FloatRect bounds;
m_private->getRelativeBounds(&container, bounds, containerTransform);
offsetContainer = WebAXObject(container);
boundsInContainer = WebFloatRect(bounds);
}
void WebAXObject::scrollToMakeVisible() const {
if (!isDetached())
m_private->scrollToMakeVisible();
}
void WebAXObject::scrollToMakeVisibleWithSubFocus(
const WebRect& subfocus) const {
if (!isDetached())
m_private->scrollToMakeVisibleWithSubFocus(subfocus);
}
void WebAXObject::scrollToGlobalPoint(const WebPoint& point) const {
if (!isDetached())
m_private->scrollToGlobalPoint(point);
}
WebAXObject::WebAXObject(AXObject* object) : m_private(object) {}
WebAXObject& WebAXObject::operator=(AXObject* object) {
m_private = object;
return *this;
}
WebAXObject::operator AXObject*() const {
return m_private.get();
}
} // namespace blink