summaryrefslogtreecommitdiffstats
path: root/WebCore/dom/InputElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/dom/InputElement.cpp')
-rw-r--r--WebCore/dom/InputElement.cpp174
1 files changed, 172 insertions, 2 deletions
diff --git a/WebCore/dom/InputElement.cpp b/WebCore/dom/InputElement.cpp
index 52812f9..3459906 100644
--- a/WebCore/dom/InputElement.cpp
+++ b/WebCore/dom/InputElement.cpp
@@ -22,6 +22,15 @@
#include "InputElement.h"
#include "BeforeTextInsertedEvent.h"
+
+#if ENABLE(WCSS)
+#include "CSSPropertyNames.h"
+#include "CSSRule.h"
+#include "CSSRuleList.h"
+#include "CSSStyleRule.h"
+#include "CSSStyleSelector.h"
+#endif
+
#include "Chrome.h"
#include "ChromeClient.h"
#include "Document.h"
@@ -138,6 +147,14 @@ void InputElement::setValueFromRenderer(InputElementData& data, InputElement* in
String InputElement::sanitizeValue(const InputElement* inputElement, const String& proposedValue)
{
+#if ENABLE(WCSS)
+ InputElementData data = const_cast<InputElement*>(inputElement)->data();
+ if (!isConformToInputMask(data, proposedValue)) {
+ if (isConformToInputMask(data, data.value()))
+ return data.value();
+ return String();
+ }
+#endif
return InputElement::sanitizeUserInputValue(inputElement, proposedValue, s_maximumLength);
}
@@ -172,8 +189,12 @@ void InputElement::handleBeforeTextInsertedEvent(InputElementData& data, InputEl
// RenderTextControlSingleLine::subtreeHasChanged() in some cases.
unsigned oldLength = numGraphemeClusters(toRenderTextControlSingleLine(element->renderer())->text());
- // selection() may be a pre-edit text.
- unsigned selectionLength = numGraphemeClusters(plainText(element->document()->frame()->selection()->selection().toNormalizedRange().get()));
+ // selectionLength represents the selection length of this text field to be
+ // removed by this insertion.
+ // If the text field has no focus, we don't need to take account of the
+ // selection length. The selection is the source of text drag-and-drop in
+ // that case, and nothing in the text field will be removed.
+ unsigned selectionLength = element->focused() ? numGraphemeClusters(plainText(element->document()->frame()->selection()->selection().toNormalizedRange().get())) : 0;
ASSERT(oldLength >= selectionLength);
// Selected characters will be removed by the next text event.
@@ -183,6 +204,18 @@ void InputElement::handleBeforeTextInsertedEvent(InputElementData& data, InputEl
// Truncate the inserted text to avoid violating the maxLength and other constraints.
BeforeTextInsertedEvent* textEvent = static_cast<BeforeTextInsertedEvent*>(event);
+#if ENABLE(WCSS)
+ RefPtr<Range> range = element->document()->frame()->selection()->selection().toNormalizedRange();
+ String candidateString = toRenderTextControlSingleLine(element->renderer())->text();
+ if (selectionLength)
+ candidateString.replace(range->startOffset(), range->endOffset(), textEvent->text());
+ else
+ candidateString.insert(textEvent->text(), range->startOffset());
+ if (!isConformToInputMask(inputElement->data(), candidateString)) {
+ textEvent->setText("");
+ return;
+ }
+#endif
textEvent->setText(sanitizeUserInputValue(inputElement, textEvent->text(), appendableLength));
}
@@ -234,6 +267,10 @@ InputElementData::InputElementData()
, m_maxLength(InputElement::s_maximumLength)
, m_cachedSelectionStart(-1)
, m_cachedSelectionEnd(-1)
+#if ENABLE(WCSS)
+ , m_inputFormatMask("*m")
+ , m_maxInputCharsAllowed(InputElement::s_maximumLength)
+#endif
{
}
@@ -255,4 +292,137 @@ InputElement* toInputElement(Element* element)
return 0;
}
+#if ENABLE(WCSS)
+static inline const AtomicString& formatCodes()
+{
+ DEFINE_STATIC_LOCAL(AtomicString, codes, ("AaNnXxMm"));
+ return codes;
+}
+
+static unsigned cursorPositionToMaskIndex(const String& inputFormatMask, unsigned cursorPosition)
+{
+ UChar mask;
+ int index = -1;
+ do {
+ mask = inputFormatMask[++index];
+ if (mask == '\\')
+ ++index;
+ else if (mask == '*' || (isASCIIDigit(mask) && mask != '0')) {
+ index = inputFormatMask.length() - 1;
+ break;
+ }
+ } while (cursorPosition--);
+
+ return index;
+}
+
+bool InputElement::isConformToInputMask(const InputElementData& data, const String& inputChars)
+{
+ for (unsigned i = 0; i < inputChars.length(); ++i)
+ if (!isConformToInputMask(data, inputChars[i], i))
+ return false;
+ return true;
+}
+
+bool InputElement::isConformToInputMask(const InputElementData& data, UChar inChar, unsigned cursorPosition)
+{
+ String inputFormatMask = data.inputFormatMask();
+
+ if (inputFormatMask.isEmpty() || inputFormatMask == "*M" || inputFormatMask == "*m")
+ return true;
+
+ if (cursorPosition >= data.maxInputCharsAllowed())
+ return false;
+
+ unsigned maskIndex = cursorPositionToMaskIndex(inputFormatMask, cursorPosition);
+ bool ok = true;
+ UChar mask = inputFormatMask[maskIndex];
+ // Match the inputed character with input mask
+ switch (mask) {
+ case 'A':
+ ok = !isASCIIDigit(inChar) && !isASCIILower(inChar) && isASCIIPrintable(inChar);
+ break;
+ case 'a':
+ ok = !isASCIIDigit(inChar) && !isASCIIUpper(inChar) && isASCIIPrintable(inChar);
+ break;
+ case 'N':
+ ok = isASCIIDigit(inChar);
+ break;
+ case 'n':
+ ok = !isASCIIAlpha(inChar) && isASCIIPrintable(inChar);
+ break;
+ case 'X':
+ ok = !isASCIILower(inChar) && isASCIIPrintable(inChar);
+ break;
+ case 'x':
+ ok = !isASCIIUpper(inChar) && isASCIIPrintable(inChar);
+ break;
+ case 'M':
+ case 'm':
+ ok = isASCIIPrintable(inChar);
+ break;
+ default:
+ ok = (mask == inChar);
+ break;
+ }
+
+ return ok;
+}
+
+String InputElement::validateInputMask(InputElementData& data, String& inputMask)
+{
+ inputMask.replace("\\\\", "\\");
+
+ bool isValid = true;
+ bool hasWildcard = false;
+ unsigned escapeCharCount = 0;
+ unsigned maskLength = inputMask.length();
+ UChar formatCode;
+ for (unsigned i = 0; i < maskLength; ++i) {
+ formatCode = inputMask[i];
+ if (formatCodes().find(formatCode) == -1) {
+ if (formatCode == '*' || (isASCIIDigit(formatCode) && formatCode != '0')) {
+ // Validate codes which ends with '*f' or 'nf'
+ formatCode = inputMask[++i];
+ if ((i + 1 != maskLength) || formatCodes().find(formatCode) == -1) {
+ isValid = false;
+ break;
+ }
+ hasWildcard = true;
+ } else if (formatCode == '\\') {
+ // skip over the next mask character
+ ++i;
+ ++escapeCharCount;
+ } else {
+ isValid = false;
+ break;
+ }
+ }
+ }
+
+ if (!isValid)
+ return String();
+ // calculate the number of characters allowed to be entered by input mask
+ unsigned allowedLength = maskLength;
+ if (escapeCharCount)
+ allowedLength -= escapeCharCount;
+
+ if (hasWildcard) {
+ formatCode = inputMask[maskLength - 2];
+ if (formatCode == '*')
+ allowedLength = data.maxInputCharsAllowed();
+ else {
+ unsigned leftLen = String(&formatCode).toInt();
+ allowedLength = leftLen + allowedLength - 2;
+ }
+ }
+
+ if (allowedLength < data.maxInputCharsAllowed())
+ data.setMaxInputCharsAllowed(allowedLength);
+
+ return inputMask;
+}
+
+#endif
+
}