2 * Copyright (C) 2008, 2009, 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "core/accessibility/AXObject.h"
32 #include "core/accessibility/AXObjectCache.h"
33 #include "core/dom/NodeTraversal.h"
34 #include "core/editing/VisibleUnits.h"
35 #include "core/editing/htmlediting.h"
36 #include "core/frame/LocalFrame.h"
37 #include "core/rendering/RenderListItem.h"
38 #include "core/rendering/RenderTheme.h"
39 #include "core/rendering/RenderView.h"
40 #include "platform/UserGestureIndicator.h"
41 #include "platform/text/PlatformLocale.h"
42 #include "wtf/StdLibExtras.h"
43 #include "wtf/text/WTFString.h"
45 using blink::WebLocalizedString;
49 using namespace HTMLNames;
51 typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;
55 AccessibilityRole webcoreRole;
58 static ARIARoleMap* createARIARoleMap()
60 const RoleEntry roles[] = {
61 { "alert", AlertRole },
62 { "alertdialog", AlertDialogRole },
63 { "application", ApplicationRole },
64 { "article", ArticleRole },
65 { "banner", BannerRole },
66 { "button", ButtonRole },
67 { "checkbox", CheckBoxRole },
68 { "complementary", ComplementaryRole },
69 { "contentinfo", ContentInfoRole },
70 { "dialog", DialogRole },
71 { "directory", DirectoryRole },
73 { "gridcell", CellRole },
74 { "columnheader", ColumnHeaderRole },
75 { "combobox", ComboBoxRole },
76 { "definition", DefinitionRole },
77 { "document", DocumentRole },
78 { "rowheader", RowHeaderRole },
79 { "group", GroupRole },
80 { "heading", HeadingRole },
84 { "listitem", ListItemRole },
85 { "listbox", ListBoxRole },
87 // "option" isn't here because it may map to different roles depending on the parent element's role
89 { "marquee", MarqueeRole },
92 { "menubar", MenuBarRole },
93 { "menuitem", MenuItemRole },
94 { "menuitemcheckbox", MenuItemRole },
95 { "menuitemradio", MenuItemRole },
97 { "navigation", NavigationRole },
98 { "option", ListBoxOptionRole },
99 { "presentation", PresentationalRole },
100 { "progressbar", ProgressIndicatorRole },
101 { "radio", RadioButtonRole },
102 { "radiogroup", RadioGroupRole },
103 { "region", RegionRole },
105 { "scrollbar", ScrollBarRole },
106 { "search", SearchRole },
107 { "separator", SplitterRole },
108 { "slider", SliderRole },
109 { "spinbutton", SpinButtonRole },
110 { "status", StatusRole },
112 { "tablist", TabListRole },
113 { "tabpanel", TabPanelRole },
114 { "text", StaticTextRole },
115 { "textbox", TextAreaRole },
116 { "timer", TimerRole },
117 { "toolbar", ToolbarRole },
118 { "tooltip", UserInterfaceTooltipRole },
119 { "tree", TreeRole },
120 { "treegrid", TreeGridRole },
121 { "treeitem", TreeItemRole }
123 ARIARoleMap* roleMap = new ARIARoleMap;
125 for (size_t i = 0; i < WTF_ARRAY_LENGTH(roles); ++i)
126 roleMap->set(roles[i].ariaRole, roles[i].webcoreRole);
132 , m_haveChildren(false)
133 , m_role(UnknownRole)
134 , m_lastKnownIsIgnoredValue(DefaultBehavior)
139 AXObject::~AXObject()
141 ASSERT(isDetached());
144 void AXObject::detach()
146 // Clear any children and call detachFromParent on them so that
147 // no children are left with dangling pointers to their parent.
153 bool AXObject::isDetached() const
158 AXObjectCache* AXObject::axObjectCache() const
160 Document* doc = document();
162 return doc->axObjectCache();
166 bool AXObject::isARIATextControl() const
168 return ariaRoleAttribute() == TextAreaRole || ariaRoleAttribute() == TextFieldRole;
171 bool AXObject::isButton() const
173 AccessibilityRole role = roleValue();
175 return role == ButtonRole || role == PopUpButtonRole || role == ToggleButtonRole;
178 bool AXObject::isLandmarkRelated() const
180 switch (roleValue()) {
181 case ApplicationRole:
184 case ComplementaryRole:
185 case ContentInfoRole:
197 bool AXObject::isMenuRelated() const
199 switch (roleValue()) {
210 bool AXObject::isTextControl() const
212 switch (roleValue()) {
222 bool AXObject::isClickable() const
224 switch (roleValue()) {
229 case EditableTextRole:
230 case ImageMapLinkRole:
232 case ListBoxOptionRole:
234 case PopUpButtonRole:
235 case RadioButtonRole:
239 case ToggleButtonRole:
246 bool AXObject::isExpanded() const
248 if (equalIgnoringCase(getAttribute(aria_expandedAttr), "true"))
254 bool AXObject::accessibilityIsIgnored() const
256 AXObjectCache* cache = axObjectCache();
260 AXComputedObjectAttributeCache* attributeCache = cache->computedObjectAttributeCache();
261 if (attributeCache) {
262 AXObjectInclusion ignored = attributeCache->getIgnored(axObjectID());
268 case DefaultBehavior:
273 bool result = computeAccessibilityIsIgnored();
276 attributeCache->setIgnored(axObjectID(), result ? IgnoreObject : IncludeObject);
281 bool AXObject::accessibilityIsIgnoredByDefault() const
283 return defaultObjectInclusion() == IgnoreObject;
286 AXObjectInclusion AXObject::accessibilityPlatformIncludesObject() const
288 if (isMenuListPopup() || isMenuListOption())
289 return IncludeObject;
291 return DefaultBehavior;
294 AXObjectInclusion AXObject::defaultObjectInclusion() const
296 if (isInertOrAriaHidden())
299 if (isPresentationalChildOfAriaRole())
302 return accessibilityPlatformIncludesObject();
305 bool AXObject::isInertOrAriaHidden() const
307 bool mightBeInInertSubtree = true;
308 for (const AXObject* object = this; object; object = object->parentObject()) {
309 if (equalIgnoringCase(object->getAttribute(aria_hiddenAttr), "true"))
311 if (mightBeInInertSubtree && object->node()) {
312 if (object->node()->isInert())
314 mightBeInInertSubtree = false;
321 bool AXObject::lastKnownIsIgnoredValue()
323 if (m_lastKnownIsIgnoredValue == DefaultBehavior)
324 m_lastKnownIsIgnoredValue = accessibilityIsIgnored() ? IgnoreObject : IncludeObject;
326 return m_lastKnownIsIgnoredValue == IgnoreObject;
329 void AXObject::setLastKnownIsIgnoredValue(bool isIgnored)
331 m_lastKnownIsIgnoredValue = isIgnored ? IgnoreObject : IncludeObject;
334 // Lacking concrete evidence of orientation, horizontal means width > height. vertical is height > width;
335 AccessibilityOrientation AXObject::orientation() const
337 LayoutRect bounds = elementRect();
338 if (bounds.size().width() > bounds.size().height())
339 return AccessibilityOrientationHorizontal;
340 if (bounds.size().height() > bounds.size().width())
341 return AccessibilityOrientationVertical;
343 // A tie goes to horizontal.
344 return AccessibilityOrientationHorizontal;
347 static String queryString(WebLocalizedString::Name name)
349 return Locale::defaultLocale().queryString(name);
352 String AXObject::actionVerb() const
354 // FIXME: Need to add verbs for select elements.
356 switch (roleValue()) {
358 case ToggleButtonRole:
359 return queryString(WebLocalizedString::AXButtonActionVerb);
362 return queryString(WebLocalizedString::AXTextFieldActionVerb);
363 case RadioButtonRole:
364 return queryString(WebLocalizedString::AXRadioButtonActionVerb);
366 return queryString(isChecked() ? WebLocalizedString::AXCheckedCheckBoxActionVerb : WebLocalizedString::AXUncheckedCheckBoxActionVerb);
368 return queryString(WebLocalizedString::AXLinkActionVerb);
369 case PopUpButtonRole:
372 case MenuListPopupRole:
376 return emptyString();
380 AccessibilityButtonState AXObject::checkboxOrRadioValue() const
382 // If this is a real checkbox or radio button, AXRenderObject will handle.
383 // If it's an ARIA checkbox or radio, the aria-checked attribute should be used.
385 const AtomicString& result = getAttribute(aria_checkedAttr);
386 if (equalIgnoringCase(result, "true"))
387 return ButtonStateOn;
388 if (equalIgnoringCase(result, "mixed"))
389 return ButtonStateMixed;
391 return ButtonStateOff;
394 bool AXObject::ariaIsMultiline() const
396 return equalIgnoringCase(getAttribute(aria_multilineAttr), "true");
399 bool AXObject::ariaPressedIsPresent() const
401 return !getAttribute(aria_pressedAttr).isEmpty();
404 bool AXObject::supportsARIAAttributes() const
406 return supportsARIALiveRegion()
407 || supportsARIADragging()
408 || supportsARIADropping()
409 || supportsARIAFlowTo()
410 || supportsARIAOwns()
411 || hasAttribute(aria_labelAttr);
414 bool AXObject::supportsRangeValue() const
416 return isProgressIndicator()
422 void AXObject::ariaTreeRows(AccessibilityChildrenVector& result)
424 AccessibilityChildrenVector axChildren = children();
425 unsigned count = axChildren.size();
426 for (unsigned k = 0; k < count; ++k) {
427 AXObject* obj = axChildren[k].get();
429 // Add tree items as the rows.
430 if (obj->roleValue() == TreeItemRole)
433 // Now see if this item also has rows hiding inside of it.
434 obj->ariaTreeRows(result);
438 bool AXObject::supportsARIALiveRegion() const
440 const AtomicString& liveRegion = ariaLiveRegionStatus();
441 return equalIgnoringCase(liveRegion, "polite") || equalIgnoringCase(liveRegion, "assertive");
444 void AXObject::markCachedElementRectDirty() const
446 for (unsigned i = 0; i < m_children.size(); ++i)
447 m_children[i].get()->markCachedElementRectDirty();
450 IntPoint AXObject::clickPoint()
452 LayoutRect rect = elementRect();
453 return roundedIntPoint(LayoutPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2));
456 IntRect AXObject::boundingBoxForQuads(RenderObject* obj, const Vector<FloatQuad>& quads)
462 size_t count = quads.size();
467 for (size_t i = 0; i < count; ++i) {
468 IntRect r = quads[i].enclosingBoundingBox();
470 if (obj->style()->hasAppearance())
471 RenderTheme::theme().adjustRepaintRect(obj, r);
478 AXObject* AXObject::elementAccessibilityHitTest(const IntPoint& point) const
480 // Send the hit test back into the sub-frame if necessary.
481 if (isAttachment()) {
482 Widget* widget = widgetForAttachmentView();
483 // Normalize the point for the widget's bounds.
484 if (widget && widget->isFrameView())
485 return axObjectCache()->getOrCreate(widget)->accessibilityHitTest(IntPoint(point - widget->frameRect().location()));
488 // Check if there are any mock elements that need to be handled.
489 size_t count = m_children.size();
490 for (size_t k = 0; k < count; k++) {
491 if (m_children[k]->isMockObject() && m_children[k]->elementRect().contains(point))
492 return m_children[k]->elementAccessibilityHitTest(point);
495 return const_cast<AXObject*>(this);
498 const AXObject::AccessibilityChildrenVector& AXObject::children()
500 updateChildrenIfNecessary();
505 AXObject* AXObject::parentObjectUnignored() const
508 for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) {
514 AXObject* AXObject::firstAccessibleObjectFromNode(const Node* node)
519 AXObjectCache* cache = node->document().axObjectCache();
520 AXObject* accessibleObject = cache->getOrCreate(node->renderer());
521 while (accessibleObject && accessibleObject->accessibilityIsIgnored()) {
522 node = NodeTraversal::next(*node);
524 while (node && !node->renderer())
525 node = NodeTraversal::nextSkippingChildren(*node);
530 accessibleObject = cache->getOrCreate(node->renderer());
533 return accessibleObject;
536 void AXObject::updateChildrenIfNecessary()
542 void AXObject::clearChildren()
544 // Some objects have weak pointers to their parents and those associations need to be detached.
545 size_t length = m_children.size();
546 for (size_t i = 0; i < length; i++)
547 m_children[i]->detachFromParent();
550 m_haveChildren = false;
553 AXObject* AXObject::focusedUIElement() const
555 Document* doc = document();
559 Page* page = doc->page();
563 return AXObjectCache::focusedUIElementForPage(page);
566 Document* AXObject::document() const
568 FrameView* frameView = documentFrameView();
572 return frameView->frame().document();
575 FrameView* AXObject::documentFrameView() const
577 const AXObject* object = this;
578 while (object && !object->isAXRenderObject())
579 object = object->parentObject();
584 return object->documentFrameView();
587 String AXObject::language() const
589 const AtomicString& lang = getAttribute(langAttr);
593 AXObject* parent = parentObject();
595 // as a last resort, fall back to the content language specified in the meta tag
597 Document* doc = document();
599 return doc->contentLanguage();
603 return parent->language();
606 bool AXObject::hasAttribute(const QualifiedName& attribute) const
608 Node* elementNode = node();
612 if (!elementNode->isElementNode())
615 Element* element = toElement(elementNode);
616 return element->fastHasAttribute(attribute);
619 const AtomicString& AXObject::getAttribute(const QualifiedName& attribute) const
621 Node* elementNode = node();
625 if (!elementNode->isElementNode())
628 Element* element = toElement(elementNode);
629 return element->fastGetAttribute(attribute);
632 bool AXObject::press() const
634 Element* actionElem = actionElement();
637 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
638 actionElem->accessKeyAction(true);
642 void AXObject::scrollToMakeVisible() const
644 IntRect objectRect = pixelSnappedIntRect(elementRect());
645 objectRect.setLocation(IntPoint());
646 scrollToMakeVisibleWithSubFocus(objectRect);
649 // This is a 1-dimensional scroll offset helper function that's applied
650 // separately in the horizontal and vertical directions, because the
651 // logic is the same. The goal is to compute the best scroll offset
652 // in order to make an object visible within a viewport.
654 // In case the whole object cannot fit, you can specify a
655 // subfocus - a smaller region within the object that should
656 // be prioritized. If the whole object can fit, the subfocus is
659 // Example: the viewport is scrolled to the right just enough
660 // that the object is in view.
662 // +----------Viewport---------+
667 // +----------Viewport---------+
671 // When constraints cannot be fully satisfied, the min
672 // (left/top) position takes precedence over the max (right/bottom).
674 // Note that the return value represents the ideal new scroll offset.
675 // This may be out of range - the calling function should clip this
676 // to the available range.
677 static int computeBestScrollOffset(int currentScrollOffset, int subfocusMin, int subfocusMax, int objectMin, int objectMax, int viewportMin, int viewportMax)
679 int viewportSize = viewportMax - viewportMin;
681 // If the focus size is larger than the viewport size, shrink it in the
682 // direction of subfocus.
683 if (objectMax - objectMin > viewportSize) {
684 // Subfocus must be within focus:
685 subfocusMin = std::max(subfocusMin, objectMin);
686 subfocusMax = std::min(subfocusMax, objectMax);
688 // Subfocus must be no larger than the viewport size; favor top/left.
689 if (subfocusMax - subfocusMin > viewportSize)
690 subfocusMax = subfocusMin + viewportSize;
692 if (subfocusMin + viewportSize > objectMax) {
693 objectMin = objectMax - viewportSize;
695 objectMin = subfocusMin;
696 objectMax = subfocusMin + viewportSize;
700 // Exit now if the focus is already within the viewport.
701 if (objectMin - currentScrollOffset >= viewportMin
702 && objectMax - currentScrollOffset <= viewportMax)
703 return currentScrollOffset;
705 // Scroll left if we're too far to the right.
706 if (objectMax - currentScrollOffset > viewportMax)
707 return objectMax - viewportMax;
709 // Scroll right if we're too far to the left.
710 if (objectMin - currentScrollOffset < viewportMin)
711 return objectMin - viewportMin;
713 ASSERT_NOT_REACHED();
715 // This shouldn't happen.
716 return currentScrollOffset;
719 void AXObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const
721 // Search up the parent chain until we find the first one that's scrollable.
722 AXObject* scrollParent = parentObject();
723 ScrollableArea* scrollableArea = 0;
724 while (scrollParent) {
725 scrollableArea = scrollParent->getScrollableAreaIfScrollable();
728 scrollParent = scrollParent->parentObject();
733 IntRect objectRect = pixelSnappedIntRect(elementRect());
734 IntPoint scrollPosition = scrollableArea->scrollPosition();
735 IntRect scrollVisibleRect = scrollableArea->visibleContentRect();
737 int desiredX = computeBestScrollOffset(
739 objectRect.x() + subfocus.x(), objectRect.x() + subfocus.maxX(),
740 objectRect.x(), objectRect.maxX(),
741 0, scrollVisibleRect.width());
742 int desiredY = computeBestScrollOffset(
744 objectRect.y() + subfocus.y(), objectRect.y() + subfocus.maxY(),
745 objectRect.y(), objectRect.maxY(),
746 0, scrollVisibleRect.height());
748 scrollParent->scrollTo(IntPoint(desiredX, desiredY));
750 // Recursively make sure the scroll parent itself is visible.
751 if (scrollParent->parentObject())
752 scrollParent->scrollToMakeVisible();
755 void AXObject::scrollToGlobalPoint(const IntPoint& globalPoint) const
757 // Search up the parent chain and create a vector of all scrollable parent objects
758 // and ending with this object itself.
759 Vector<const AXObject*> objects;
760 AXObject* parentObject;
761 for (parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
762 if (parentObject->getScrollableAreaIfScrollable())
763 objects.prepend(parentObject);
765 objects.append(this);
767 // Start with the outermost scrollable (the main window) and try to scroll the
768 // next innermost object to the given point.
769 int offsetX = 0, offsetY = 0;
770 IntPoint point = globalPoint;
771 size_t levels = objects.size() - 1;
772 for (size_t i = 0; i < levels; i++) {
773 const AXObject* outer = objects[i];
774 const AXObject* inner = objects[i + 1];
776 ScrollableArea* scrollableArea = outer->getScrollableAreaIfScrollable();
778 IntRect innerRect = inner->isAXScrollView() ? pixelSnappedIntRect(inner->parentObject()->elementRect()) : pixelSnappedIntRect(inner->elementRect());
779 IntRect objectRect = innerRect;
780 IntPoint scrollPosition = scrollableArea->scrollPosition();
782 // Convert the object rect into local coordinates.
783 objectRect.move(offsetX, offsetY);
784 if (!outer->isAXScrollView())
785 objectRect.move(scrollPosition.x(), scrollPosition.y());
787 int desiredX = computeBestScrollOffset(
789 objectRect.x(), objectRect.maxX(),
790 objectRect.x(), objectRect.maxX(),
791 point.x(), point.x());
792 int desiredY = computeBestScrollOffset(
794 objectRect.y(), objectRect.maxY(),
795 objectRect.y(), objectRect.maxY(),
796 point.y(), point.y());
797 outer->scrollTo(IntPoint(desiredX, desiredY));
799 if (outer->isAXScrollView() && !inner->isAXScrollView()) {
800 // If outer object we just scrolled is a scroll view (main window or iframe) but the
801 // inner object is not, keep track of the coordinate transformation to apply to
802 // future nested calculations.
803 scrollPosition = scrollableArea->scrollPosition();
804 offsetX -= (scrollPosition.x() + point.x());
805 offsetY -= (scrollPosition.y() + point.y());
806 point.move(scrollPosition.x() - innerRect.x(), scrollPosition.y() - innerRect.y());
807 } else if (inner->isAXScrollView()) {
808 // Otherwise, if the inner object is a scroll view, reset the coordinate transformation.
815 void AXObject::notifyIfIgnoredValueChanged()
817 bool isIgnored = accessibilityIsIgnored();
818 if (lastKnownIsIgnoredValue() != isIgnored) {
819 axObjectCache()->childrenChanged(parentObject());
820 setLastKnownIsIgnoredValue(isIgnored);
824 void AXObject::selectionChanged()
826 if (AXObject* parent = parentObjectIfExists())
827 parent->selectionChanged();
830 int AXObject::lineForPosition(const VisiblePosition& visiblePos) const
832 if (visiblePos.isNull() || !node())
835 // If the position is not in the same editable region as this AX object, return -1.
836 Node* containerNode = visiblePos.deepEquivalent().containerNode();
837 if (!containerNode->containsIncludingShadowDOM(node()) && !node()->containsIncludingShadowDOM(containerNode))
841 VisiblePosition currentVisiblePos = visiblePos;
842 VisiblePosition savedVisiblePos;
844 // move up until we get to the top
845 // FIXME: This only takes us to the top of the rootEditableElement, not the top of the
848 savedVisiblePos = currentVisiblePos;
849 VisiblePosition prevVisiblePos = previousLinePosition(currentVisiblePos, 0, HasEditableAXRole);
850 currentVisiblePos = prevVisiblePos;
852 } while (currentVisiblePos.isNotNull() && !(inSameLine(currentVisiblePos, savedVisiblePos)));
857 bool AXObject::isARIAControl(AccessibilityRole ariaRole)
859 return isARIAInput(ariaRole) || ariaRole == TextAreaRole || ariaRole == ButtonRole
860 || ariaRole == ComboBoxRole || ariaRole == SliderRole;
863 bool AXObject::isARIAInput(AccessibilityRole ariaRole)
865 return ariaRole == RadioButtonRole || ariaRole == CheckBoxRole || ariaRole == TextFieldRole;
868 AccessibilityRole AXObject::ariaRoleToWebCoreRole(const String& value)
870 ASSERT(!value.isEmpty());
872 static const ARIARoleMap* roleMap = createARIARoleMap();
874 Vector<String> roleVector;
875 value.split(' ', roleVector);
876 AccessibilityRole role = UnknownRole;
877 unsigned size = roleVector.size();
878 for (unsigned i = 0; i < size; ++i) {
879 String roleName = roleVector[i];
880 role = roleMap->get(roleName);
888 AccessibilityRole AXObject::buttonRoleType() const
890 // If aria-pressed is present, then it should be exposed as a toggle button.
891 // http://www.w3.org/TR/wai-aria/states_and_properties#aria-pressed
892 if (ariaPressedIsPresent())
893 return ToggleButtonRole;
895 return PopUpButtonRole;
896 // We don't contemplate RadioButtonRole, as it depends on the input