1/* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#if ENABLE(INPUT_MULTIPLE_FIELDS_UI) 28#include "core/html/shadow/DateTimeSymbolicFieldElement.h" 29 30#include "core/events/KeyboardEvent.h" 31#include "platform/fonts/Font.h" 32#include "platform/text/TextBreakIterator.h" 33#include "wtf/text/StringBuilder.h" 34#include "wtf/unicode/Unicode.h" 35 36namespace blink { 37 38static AtomicString makeVisibleEmptyValue(const Vector<String>& symbols) 39{ 40 unsigned maximumLength = 0; 41 for (unsigned index = 0; index < symbols.size(); ++index) 42 maximumLength = std::max(maximumLength, numGraphemeClusters(symbols[index])); 43 StringBuilder builder; 44 builder.reserveCapacity(maximumLength); 45 for (unsigned length = 0; length < maximumLength; ++length) 46 builder.append('-'); 47 return builder.toAtomicString(); 48} 49 50DateTimeSymbolicFieldElement::DateTimeSymbolicFieldElement(Document& document, FieldOwner& fieldOwner, const Vector<String>& symbols, int minimum, int maximum) 51 : DateTimeFieldElement(document, fieldOwner) 52 , m_symbols(symbols) 53 , m_visibleEmptyValue(makeVisibleEmptyValue(symbols)) 54 , m_selectedIndex(-1) 55 , m_typeAhead(this) 56 , m_minimumIndex(minimum) 57 , m_maximumIndex(maximum) 58{ 59 ASSERT(!symbols.isEmpty()); 60 ASSERT(m_minimumIndex >= 0); 61 ASSERT_WITH_SECURITY_IMPLICATION(m_maximumIndex < static_cast<int>(m_symbols.size())); 62 ASSERT(m_minimumIndex <= m_maximumIndex); 63} 64 65float DateTimeSymbolicFieldElement::maximumWidth(const Font& font) 66{ 67 float maximumWidth = font.width(visibleEmptyValue()); 68 for (unsigned index = 0; index < m_symbols.size(); ++index) 69 maximumWidth = std::max(maximumWidth, font.width(m_symbols[index])); 70 return maximumWidth + DateTimeFieldElement::maximumWidth(font); 71} 72 73void DateTimeSymbolicFieldElement::handleKeyboardEvent(KeyboardEvent* keyboardEvent) 74{ 75 if (keyboardEvent->type() != EventTypeNames::keypress) 76 return; 77 78 const UChar charCode = WTF::Unicode::toLower(keyboardEvent->charCode()); 79 if (charCode < ' ') 80 return; 81 82 keyboardEvent->setDefaultHandled(); 83 84 int index = m_typeAhead.handleEvent(keyboardEvent, TypeAhead::MatchPrefix | TypeAhead::CycleFirstChar | TypeAhead::MatchIndex); 85 if (index < 0) 86 return; 87 setValueAsInteger(index, DispatchEvent); 88} 89 90bool DateTimeSymbolicFieldElement::hasValue() const 91{ 92 return m_selectedIndex >= 0; 93} 94 95void DateTimeSymbolicFieldElement::initialize(const AtomicString& pseudo, const String& axHelpText) 96{ 97 // The minimum and maximum below are exposed to users, and 1-based numbers 98 // are natural for symbolic fields. For example, the minimum value of a 99 // month field should be 1, not 0. 100 DateTimeFieldElement::initialize(pseudo, axHelpText, m_minimumIndex + 1, m_maximumIndex + 1); 101} 102 103void DateTimeSymbolicFieldElement::setEmptyValue(EventBehavior eventBehavior) 104{ 105 if (isDisabled()) 106 return; 107 m_selectedIndex = invalidIndex; 108 updateVisibleValue(eventBehavior); 109} 110 111void DateTimeSymbolicFieldElement::setValueAsInteger(int newSelectedIndex, EventBehavior eventBehavior) 112{ 113 m_selectedIndex = std::max(0, std::min(newSelectedIndex, static_cast<int>(m_symbols.size() - 1))); 114 updateVisibleValue(eventBehavior); 115} 116 117void DateTimeSymbolicFieldElement::stepDown() 118{ 119 if (hasValue()) { 120 if (!indexIsInRange(--m_selectedIndex)) 121 m_selectedIndex = m_maximumIndex; 122 } else 123 m_selectedIndex = m_maximumIndex; 124 updateVisibleValue(DispatchEvent); 125} 126 127void DateTimeSymbolicFieldElement::stepUp() 128{ 129 if (hasValue()) { 130 if (!indexIsInRange(++m_selectedIndex)) 131 m_selectedIndex = m_minimumIndex; 132 } else 133 m_selectedIndex = m_minimumIndex; 134 updateVisibleValue(DispatchEvent); 135} 136 137String DateTimeSymbolicFieldElement::value() const 138{ 139 return hasValue() ? m_symbols[m_selectedIndex] : emptyString(); 140} 141 142int DateTimeSymbolicFieldElement::valueAsInteger() const 143{ 144 return m_selectedIndex; 145} 146 147int DateTimeSymbolicFieldElement::valueForARIAValueNow() const 148{ 149 // Synchronize with minimum/maximum adjustment in initialize(). 150 return m_selectedIndex + 1; 151} 152 153String DateTimeSymbolicFieldElement::visibleEmptyValue() const 154{ 155 return m_visibleEmptyValue; 156} 157 158String DateTimeSymbolicFieldElement::visibleValue() const 159{ 160 return hasValue() ? m_symbols[m_selectedIndex] : visibleEmptyValue(); 161} 162 163int DateTimeSymbolicFieldElement::indexOfSelectedOption() const 164{ 165 return m_selectedIndex; 166} 167 168int DateTimeSymbolicFieldElement::optionCount() const 169{ 170 return m_symbols.size(); 171} 172 173String DateTimeSymbolicFieldElement::optionAtIndex(int index) const 174{ 175 return m_symbols[index]; 176} 177 178} // namespace blink 179 180#endif 181