~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/html/HTMLTextFormControlElement.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 
3
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 
4
 *           (C) 2001 Dirk Mueller (mueller@kde.org)
 
5
 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
 
6
 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
 
7
 *
 
8
 * This library is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU Library General Public
 
10
 * License as published by the Free Software Foundation; either
 
11
 * version 2 of the License, or (at your option) any later version.
 
12
 *
 
13
 * This library is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * Library General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Library General Public License
 
19
 * along with this library; see the file COPYING.LIB.  If not, write to
 
20
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
21
 * Boston, MA 02110-1301, USA.
 
22
 *
 
23
 */
 
24
 
 
25
#include "config.h"
 
26
#include "HTMLTextFormControlElement.h"
 
27
 
 
28
#include "AXObjectCache.h"
 
29
#include "Attribute.h"
 
30
#include "ChromeClient.h"
 
31
#include "Document.h"
 
32
#include "Event.h"
 
33
#include "EventNames.h"
 
34
#include "Frame.h"
 
35
#include "HTMLBRElement.h"
 
36
#include "HTMLFormElement.h"
 
37
#include "HTMLInputElement.h"
 
38
#include "HTMLNames.h"
 
39
#include "NodeRenderingContext.h"
 
40
#include "RenderBox.h"
 
41
#include "RenderTextControl.h"
 
42
#include "RenderTheme.h"
 
43
#include "ScriptEventListener.h"
 
44
#include "Text.h"
 
45
#include "TextIterator.h"
 
46
#include <wtf/text/StringBuilder.h>
 
47
 
 
48
namespace WebCore {
 
49
 
 
50
using namespace HTMLNames;
 
51
using namespace std;
 
52
 
 
53
HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* form)
 
54
    : HTMLFormControlElementWithState(tagName, doc, form)
 
55
    , m_lastChangeWasUserEdit(false)
 
56
    , m_cachedSelectionStart(-1)
 
57
    , m_cachedSelectionEnd(-1)
 
58
    , m_cachedSelectionDirection(SelectionHasNoDirection)
 
59
{
 
60
}
 
61
 
 
62
HTMLTextFormControlElement::~HTMLTextFormControlElement()
 
63
{
 
64
}
 
65
 
 
66
bool HTMLTextFormControlElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
 
67
{
 
68
    return childContext.isOnEncapsulationBoundary() && HTMLFormControlElementWithState::childShouldCreateRenderer(childContext);
 
69
}
 
70
 
 
71
Node::InsertionNotificationRequest HTMLTextFormControlElement::insertedInto(ContainerNode* insertionPoint)
 
72
{
 
73
    HTMLFormControlElement::insertedInto(insertionPoint);
 
74
    if (!insertionPoint->inDocument())
 
75
        return InsertionDone;
 
76
    String initialValue = value();
 
77
    setTextAsOfLastFormControlChangeEvent(initialValue.isNull() ? emptyString() : initialValue);
 
78
    return InsertionDone;
 
79
}
 
80
 
 
81
void HTMLTextFormControlElement::dispatchFocusEvent(PassRefPtr<Node> oldFocusedNode)
 
82
{
 
83
    if (supportsPlaceholder())
 
84
        updatePlaceholderVisibility(false);
 
85
    handleFocusEvent();
 
86
    HTMLFormControlElementWithState::dispatchFocusEvent(oldFocusedNode);
 
87
}
 
88
 
 
89
void HTMLTextFormControlElement::dispatchBlurEvent(PassRefPtr<Node> newFocusedNode)
 
90
{
 
91
    if (supportsPlaceholder())
 
92
        updatePlaceholderVisibility(false);
 
93
    handleBlurEvent();
 
94
    HTMLFormControlElementWithState::dispatchBlurEvent(newFocusedNode);
 
95
}
 
96
 
 
97
void HTMLTextFormControlElement::defaultEventHandler(Event* event)
 
98
{
 
99
    if (event->type() == eventNames().webkitEditableContentChangedEvent && renderer() && renderer()->isTextControl()) {
 
100
        m_lastChangeWasUserEdit = true;
 
101
        subtreeHasChanged();
 
102
        return;
 
103
    }
 
104
 
 
105
    HTMLFormControlElementWithState::defaultEventHandler(event);
 
106
}
 
107
 
 
108
void HTMLTextFormControlElement::forwardEvent(Event* event)
 
109
{
 
110
    if (event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)
 
111
        return;
 
112
    innerTextElement()->defaultEventHandler(event);
 
113
}
 
114
 
 
115
String HTMLTextFormControlElement::strippedPlaceholder() const
 
116
{
 
117
    // According to the HTML5 specification, we need to remove CR and LF from
 
118
    // the attribute value.
 
119
    const AtomicString& attributeValue = getAttribute(placeholderAttr);
 
120
    if (!attributeValue.contains(newlineCharacter) && !attributeValue.contains(carriageReturn))
 
121
        return attributeValue;
 
122
 
 
123
    StringBuilder stripped;
 
124
    unsigned length = attributeValue.length();
 
125
    stripped.reserveCapacity(length);
 
126
    for (unsigned i = 0; i < length; ++i) {
 
127
        UChar character = attributeValue[i];
 
128
        if (character == newlineCharacter || character == carriageReturn)
 
129
            continue;
 
130
        stripped.append(character);
 
131
    }
 
132
    return stripped.toString();
 
133
}
 
134
 
 
135
static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; }
 
136
 
 
137
bool HTMLTextFormControlElement::isPlaceholderEmpty() const
 
138
{
 
139
    const AtomicString& attributeValue = getAttribute(placeholderAttr);
 
140
    return attributeValue.string().find(isNotLineBreak) == notFound;
 
141
}
 
142
 
 
143
bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
 
144
{
 
145
    return supportsPlaceholder()
 
146
        && isEmptyValue()
 
147
        && isEmptySuggestedValue()
 
148
        && !isPlaceholderEmpty()
 
149
        && (document()->focusedNode() != this || (renderer() && renderer()->theme()->shouldShowPlaceholderWhenFocused()))
 
150
        && (!renderer() || renderer()->style()->visibility() == VISIBLE);
 
151
}
 
152
 
 
153
void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged)
 
154
{
 
155
    if (!supportsPlaceholder())
 
156
        return;
 
157
    if (!placeholderElement() || placeholderValueChanged)
 
158
        updatePlaceholderText();
 
159
    HTMLElement* placeholder = placeholderElement();
 
160
    if (!placeholder)
 
161
        return;
 
162
    placeholder->setInlineStyleProperty(CSSPropertyVisibility, placeholderShouldBeVisible() ? "visible" : "hidden");
 
163
}
 
164
 
 
165
void HTMLTextFormControlElement::fixPlaceholderRenderer(HTMLElement* placeholder, HTMLElement* siblingElement)
 
166
{
 
167
    // FIXME: We should change the order of DOM nodes. But it makes an assertion
 
168
    // failure in editing code.
 
169
    if (!placeholder || !placeholder->renderer())
 
170
        return;
 
171
    RenderObject* placeholderRenderer = placeholder->renderer();
 
172
    RenderObject* siblingRenderer = siblingElement->renderer();
 
173
    ASSERT(siblingRenderer);
 
174
    if (placeholderRenderer->nextSibling() == siblingRenderer)
 
175
        return;
 
176
    RenderObject* parentRenderer = placeholderRenderer->parent();
 
177
    ASSERT(parentRenderer == siblingRenderer->parent());
 
178
    parentRenderer->removeChild(placeholderRenderer);
 
179
    parentRenderer->addChild(placeholderRenderer, siblingRenderer);
 
180
}
 
181
 
 
182
RenderTextControl* HTMLTextFormControlElement::textRendererAfterUpdateLayout()
 
183
{
 
184
    if (!isTextFormControl())
 
185
        return 0;
 
186
    document()->updateLayoutIgnorePendingStylesheets();
 
187
    return toRenderTextControl(renderer());
 
188
}
 
189
 
 
190
void HTMLTextFormControlElement::setSelectionStart(int start)
 
191
{
 
192
    setSelectionRange(start, max(start, selectionEnd()), selectionDirection());
 
193
}
 
194
 
 
195
void HTMLTextFormControlElement::setSelectionEnd(int end)
 
196
{
 
197
    setSelectionRange(min(end, selectionStart()), end, selectionDirection());
 
198
}
 
199
 
 
200
void HTMLTextFormControlElement::setSelectionDirection(const String& direction)
 
201
{
 
202
    setSelectionRange(selectionStart(), selectionEnd(), direction);
 
203
}
 
204
 
 
205
void HTMLTextFormControlElement::select()
 
206
{
 
207
    setSelectionRange(0, numeric_limits<int>::max(), SelectionHasNoDirection);
 
208
}
 
209
 
 
210
String HTMLTextFormControlElement::selectedText() const
 
211
{
 
212
    if (!isTextFormControl())
 
213
        return String();
 
214
    return value().substring(selectionStart(), selectionEnd() - selectionStart());
 
215
}
 
216
 
 
217
void HTMLTextFormControlElement::dispatchFormControlChangeEvent()
 
218
{
 
219
    if (m_textAsOfLastFormControlChangeEvent != value()) {
 
220
        HTMLElement::dispatchChangeEvent();
 
221
        setTextAsOfLastFormControlChangeEvent(value());
 
222
    }
 
223
    setChangedSinceLastFormControlChangeEvent(false);
 
224
}
 
225
 
 
226
static inline bool hasVisibleTextArea(RenderTextControl* textControl, HTMLElement* innerText)
 
227
{
 
228
    ASSERT(textControl);
 
229
    return textControl->style()->visibility() != HIDDEN && innerText && innerText->renderer() && innerText->renderBox()->height();
 
230
}
 
231
 
 
232
 
 
233
void HTMLTextFormControlElement::setRangeText(const String& replacement, ExceptionCode& ec)
 
234
{
 
235
    setRangeText(replacement, selectionStart(), selectionEnd(), String(), ec);
 
236
}
 
237
 
 
238
void HTMLTextFormControlElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionCode& ec)
 
239
{
 
240
    if (start > end) {
 
241
        ec = INDEX_SIZE_ERR;
 
242
        return;
 
243
    }
 
244
 
 
245
    String text = innerTextValue();
 
246
    unsigned textLength = text.length();
 
247
    unsigned replacementLength = replacement.length();
 
248
    unsigned newSelectionStart = selectionStart();
 
249
    unsigned newSelectionEnd = selectionEnd();
 
250
 
 
251
    start = std::min(start, textLength);
 
252
    end = std::min(end, textLength);
 
253
 
 
254
    if (start < end)
 
255
        text.replace(start, end - start, replacement);
 
256
    else
 
257
        text.insert(replacement, start);
 
258
 
 
259
    setInnerTextValue(text);
 
260
 
 
261
    // FIXME: What should happen to the value (as in value()) if there's no renderer?
 
262
    if (!renderer())
 
263
        return;
 
264
 
 
265
    subtreeHasChanged();
 
266
 
 
267
    if (equalIgnoringCase(selectionMode, "select")) {
 
268
        newSelectionStart = start;
 
269
        newSelectionEnd = start + replacementLength;
 
270
    } else if (equalIgnoringCase(selectionMode, "start"))
 
271
        newSelectionStart = newSelectionEnd = start;
 
272
    else if (equalIgnoringCase(selectionMode, "end"))
 
273
        newSelectionStart = newSelectionEnd = start + replacementLength;
 
274
    else {
 
275
        // Default is "preserve".
 
276
        long delta = replacementLength - (end - start);
 
277
 
 
278
        if (newSelectionStart > end)
 
279
            newSelectionStart += delta;
 
280
        else if (newSelectionStart > start)
 
281
            newSelectionStart = start;
 
282
 
 
283
        if (newSelectionEnd > end)
 
284
            newSelectionEnd += delta;
 
285
        else if (newSelectionEnd > start)
 
286
            newSelectionEnd = start + replacementLength;
 
287
    }
 
288
 
 
289
    setSelectionRange(newSelectionStart, newSelectionEnd, SelectionHasNoDirection);
 
290
}
 
291
 
 
292
void HTMLTextFormControlElement::setSelectionRange(int start, int end, const String& directionString)
 
293
{
 
294
    TextFieldSelectionDirection direction = SelectionHasNoDirection;
 
295
    if (directionString == "forward")
 
296
        direction = SelectionHasForwardDirection;
 
297
    else if (directionString == "backward")
 
298
        direction = SelectionHasBackwardDirection;
 
299
 
 
300
    return setSelectionRange(start, end, direction);
 
301
}
 
302
 
 
303
void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction)
 
304
{
 
305
    document()->updateLayoutIgnorePendingStylesheets();
 
306
 
 
307
    if (!renderer() || !renderer()->isTextControl())
 
308
        return;
 
309
 
 
310
    end = max(end, 0);
 
311
    start = min(max(start, 0), end);
 
312
 
 
313
    RenderTextControl* control = toRenderTextControl(renderer());
 
314
    if (!hasVisibleTextArea(control, innerTextElement())) {
 
315
        cacheSelection(start, end, direction);
 
316
        return;
 
317
    }
 
318
    VisiblePosition startPosition = control->visiblePositionForIndex(start);
 
319
    VisiblePosition endPosition;
 
320
    if (start == end)
 
321
        endPosition = startPosition;
 
322
    else
 
323
        endPosition = control->visiblePositionForIndex(end);
 
324
 
 
325
    // startPosition and endPosition can be null position for example when
 
326
    // "-webkit-user-select: none" style attribute is specified.
 
327
    if (startPosition.isNotNull() && endPosition.isNotNull()) {
 
328
        ASSERT(startPosition.deepEquivalent().deprecatedNode()->shadowAncestorNode() == this
 
329
            && endPosition.deepEquivalent().deprecatedNode()->shadowAncestorNode() == this);
 
330
    }
 
331
    VisibleSelection newSelection;
 
332
    if (direction == SelectionHasBackwardDirection)
 
333
        newSelection = VisibleSelection(endPosition, startPosition);
 
334
    else
 
335
        newSelection = VisibleSelection(startPosition, endPosition);
 
336
    newSelection.setIsDirectional(direction != SelectionHasNoDirection);
 
337
 
 
338
    if (Frame* frame = document()->frame())
 
339
        frame->selection()->setSelection(newSelection);
 
340
}
 
341
 
 
342
int HTMLTextFormControlElement::indexForVisiblePosition(const VisiblePosition& pos) const
 
343
{
 
344
    Position indexPosition = pos.deepEquivalent().parentAnchoredEquivalent();
 
345
    if (enclosingTextFormControl(indexPosition) != this)
 
346
        return 0;
 
347
    ExceptionCode ec = 0;
 
348
    RefPtr<Range> range = Range::create(indexPosition.document());
 
349
    range->setStart(innerTextElement(), 0, ec);
 
350
    ASSERT(!ec);
 
351
    range->setEnd(indexPosition.containerNode(), indexPosition.offsetInContainerNode(), ec);
 
352
    ASSERT(!ec);
 
353
    return TextIterator::rangeLength(range.get());
 
354
}
 
355
 
 
356
int HTMLTextFormControlElement::selectionStart() const
 
357
{
 
358
    if (!isTextFormControl())
 
359
        return 0;
 
360
    if (document()->focusedNode() != this && hasCachedSelection())
 
361
        return m_cachedSelectionStart;
 
362
 
 
363
    return computeSelectionStart();
 
364
}
 
365
 
 
366
int HTMLTextFormControlElement::computeSelectionStart() const
 
367
{
 
368
    ASSERT(isTextFormControl());
 
369
    Frame* frame = document()->frame();
 
370
    if (!frame)
 
371
        return 0;
 
372
 
 
373
    return indexForVisiblePosition(frame->selection()->start());
 
374
}
 
375
 
 
376
int HTMLTextFormControlElement::selectionEnd() const
 
377
{
 
378
    if (!isTextFormControl())
 
379
        return 0;
 
380
    if (document()->focusedNode() != this && hasCachedSelection())
 
381
        return m_cachedSelectionEnd;
 
382
    return computeSelectionEnd();
 
383
}
 
384
 
 
385
int HTMLTextFormControlElement::computeSelectionEnd() const
 
386
{
 
387
    ASSERT(isTextFormControl());
 
388
    Frame* frame = document()->frame();
 
389
    if (!frame)
 
390
        return 0;
 
391
 
 
392
    return indexForVisiblePosition(frame->selection()->end());
 
393
}
 
394
 
 
395
static const AtomicString& directionString(TextFieldSelectionDirection direction)
 
396
{
 
397
    DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::ConstructFromLiteral));
 
398
    DEFINE_STATIC_LOCAL(const AtomicString, forward, ("forward", AtomicString::ConstructFromLiteral));
 
399
    DEFINE_STATIC_LOCAL(const AtomicString, backward, ("backward", AtomicString::ConstructFromLiteral));
 
400
 
 
401
    switch (direction) {
 
402
    case SelectionHasNoDirection:
 
403
        return none;
 
404
    case SelectionHasForwardDirection:
 
405
        return forward;
 
406
    case SelectionHasBackwardDirection:
 
407
        return backward;
 
408
    }
 
409
 
 
410
    ASSERT_NOT_REACHED();
 
411
    return none;
 
412
}
 
413
 
 
414
const AtomicString& HTMLTextFormControlElement::selectionDirection() const
 
415
{
 
416
    if (!isTextFormControl())
 
417
        return directionString(SelectionHasNoDirection);
 
418
    if (document()->focusedNode() != this && hasCachedSelection())
 
419
        return directionString(m_cachedSelectionDirection);
 
420
 
 
421
    return directionString(computeSelectionDirection());
 
422
}
 
423
 
 
424
TextFieldSelectionDirection HTMLTextFormControlElement::computeSelectionDirection() const
 
425
{
 
426
    ASSERT(isTextFormControl());
 
427
    Frame* frame = document()->frame();
 
428
    if (!frame)
 
429
        return SelectionHasNoDirection;
 
430
 
 
431
    const VisibleSelection& selection = frame->selection()->selection();
 
432
    return selection.isDirectional() ? (selection.isBaseFirst() ? SelectionHasForwardDirection : SelectionHasBackwardDirection) : SelectionHasNoDirection;
 
433
}
 
434
 
 
435
static inline void setContainerAndOffsetForRange(Node* node, int offset, Node*& containerNode, int& offsetInContainer)
 
436
{
 
437
    if (node->isTextNode()) {
 
438
        containerNode = node;
 
439
        offsetInContainer = offset;
 
440
    } else {
 
441
        containerNode = node->parentNode();
 
442
        offsetInContainer = node->nodeIndex() + offset;
 
443
    }
 
444
}
 
445
 
 
446
PassRefPtr<Range> HTMLTextFormControlElement::selection() const
 
447
{
 
448
    if (!renderer() || !isTextFormControl() || !hasCachedSelection())
 
449
        return 0;
 
450
 
 
451
    int start = m_cachedSelectionStart;
 
452
    int end = m_cachedSelectionEnd;
 
453
 
 
454
    ASSERT(start <= end);
 
455
    HTMLElement* innerText = innerTextElement();
 
456
    if (!innerText)
 
457
        return 0;
 
458
 
 
459
    if (!innerText->firstChild())
 
460
        return Range::create(document(), innerText, 0, innerText, 0);
 
461
 
 
462
    int offset = 0;
 
463
    Node* startNode = 0;
 
464
    Node* endNode = 0;
 
465
    for (Node* node = innerText->firstChild(); node; node = node->traverseNextNode(innerText)) {
 
466
        ASSERT(!node->firstChild());
 
467
        ASSERT(node->isTextNode() || node->hasTagName(brTag));
 
468
        int length = node->isTextNode() ? lastOffsetInNode(node) : 1;
 
469
 
 
470
        if (offset <= start && start <= offset + length)
 
471
            setContainerAndOffsetForRange(node, start - offset, startNode, start);
 
472
 
 
473
        if (offset <= end && end <= offset + length) {
 
474
            setContainerAndOffsetForRange(node, end - offset, endNode, end);
 
475
            break;
 
476
        }
 
477
 
 
478
        offset += length;
 
479
    }
 
480
 
 
481
    if (!startNode || !endNode)
 
482
        return 0;
 
483
 
 
484
    return Range::create(document(), startNode, start, endNode, end);
 
485
}
 
486
 
 
487
void HTMLTextFormControlElement::restoreCachedSelection()
 
488
{
 
489
    setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, m_cachedSelectionDirection);
 
490
}
 
491
 
 
492
void HTMLTextFormControlElement::selectionChanged(bool userTriggered)
 
493
{
 
494
    if (!renderer() || !isTextFormControl())
 
495
        return;
 
496
 
 
497
    // selectionStart() or selectionEnd() will return cached selection when this node doesn't have focus
 
498
    cacheSelection(computeSelectionStart(), computeSelectionEnd(), computeSelectionDirection());
 
499
 
 
500
    if (Frame* frame = document()->frame()) {
 
501
        if (frame->selection()->isRange() && userTriggered)
 
502
            dispatchEvent(Event::create(eventNames().selectEvent, true, false));
 
503
    }
 
504
}
 
505
 
 
506
void HTMLTextFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
 
507
{
 
508
    if (name == placeholderAttr)
 
509
        updatePlaceholderVisibility(true);
 
510
    else if (name == onselectAttr)
 
511
        setAttributeEventListener(eventNames().selectEvent, createAttributeEventListener(this, name, value));
 
512
    else if (name == onchangeAttr)
 
513
        setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, name, value));
 
514
    else
 
515
        HTMLFormControlElementWithState::parseAttribute(name, value);
 
516
}
 
517
 
 
518
bool HTMLTextFormControlElement::lastChangeWasUserEdit() const
 
519
{
 
520
    if (!isTextFormControl())
 
521
        return false;
 
522
    return m_lastChangeWasUserEdit;
 
523
}
 
524
 
 
525
void HTMLTextFormControlElement::setInnerTextValue(const String& value)
 
526
{
 
527
    if (!isTextFormControl())
 
528
        return;
 
529
 
 
530
    bool textIsChanged = value != innerTextValue();
 
531
    if (textIsChanged || !innerTextElement()->hasChildNodes()) {
 
532
        if (textIsChanged && document() && renderer() && AXObjectCache::accessibilityEnabled())
 
533
            document()->axObjectCache()->postNotification(this, AXObjectCache::AXValueChanged, false);
 
534
 
 
535
        ExceptionCode ec = 0;
 
536
        innerTextElement()->setInnerText(value, ec);
 
537
        ASSERT(!ec);
 
538
 
 
539
        if (value.endsWith('\n') || value.endsWith('\r')) {
 
540
            innerTextElement()->appendChild(HTMLBRElement::create(document()), ec);
 
541
            ASSERT(!ec);
 
542
        }
 
543
    }
 
544
 
 
545
    setFormControlValueMatchesRenderer(true);
 
546
}
 
547
 
 
548
static String finishText(StringBuilder& result)
 
549
{
 
550
    // Remove one trailing newline; there's always one that's collapsed out by rendering.
 
551
    size_t size = result.length();
 
552
    if (size && result[size - 1] == '\n')
 
553
        result.resize(--size);
 
554
    return result.toString();
 
555
}
 
556
 
 
557
String HTMLTextFormControlElement::innerTextValue() const
 
558
{
 
559
    HTMLElement* innerText = innerTextElement();
 
560
    if (!innerText || !isTextFormControl())
 
561
        return emptyString();
 
562
 
 
563
    StringBuilder result;
 
564
    for (Node* node = innerText; node; node = node->traverseNextNode(innerText)) {
 
565
        if (node->hasTagName(brTag))
 
566
            result.append(newlineCharacter);
 
567
        else if (node->isTextNode())
 
568
            result.append(toText(node)->data());
 
569
    }
 
570
    return finishText(result);
 
571
}
 
572
 
 
573
static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
 
574
{
 
575
    RootInlineBox* next;
 
576
    for (; line; line = next) {
 
577
        next = line->nextRootBox();
 
578
        if (next && !line->endsWithBreak()) {
 
579
            ASSERT(line->lineBreakObj());
 
580
            breakNode = line->lineBreakObj()->node();
 
581
            breakOffset = line->lineBreakPos();
 
582
            line = next;
 
583
            return;
 
584
        }
 
585
    }
 
586
    breakNode = 0;
 
587
    breakOffset = 0;
 
588
}
 
589
 
 
590
String HTMLTextFormControlElement::valueWithHardLineBreaks() const
 
591
{
 
592
    // FIXME: It's not acceptable to ignore the HardWrap setting when there is no renderer.
 
593
    // While we have no evidence this has ever been a practical problem, it would be best to fix it some day.
 
594
    HTMLElement* innerText = innerTextElement();
 
595
    if (!innerText || !isTextFormControl())
 
596
        return value();
 
597
 
 
598
    RenderBlock* renderer = toRenderBlock(innerText->renderer());
 
599
    if (!renderer)
 
600
        return value();
 
601
 
 
602
    Node* breakNode;
 
603
    unsigned breakOffset;
 
604
    RootInlineBox* line = renderer->firstRootBox();
 
605
    if (!line)
 
606
        return value();
 
607
 
 
608
    getNextSoftBreak(line, breakNode, breakOffset);
 
609
 
 
610
    StringBuilder result;
 
611
    for (Node* node = innerText->firstChild(); node; node = node->traverseNextNode(innerText)) {
 
612
        if (node->hasTagName(brTag))
 
613
            result.append(newlineCharacter);
 
614
        else if (node->isTextNode()) {
 
615
            String data = toText(node)->data();
 
616
            unsigned length = data.length();
 
617
            unsigned position = 0;
 
618
            while (breakNode == node && breakOffset <= length) {
 
619
                if (breakOffset > position) {
 
620
                    result.append(data.characters() + position, breakOffset - position);
 
621
                    position = breakOffset;
 
622
                    result.append(newlineCharacter);
 
623
                }
 
624
                getNextSoftBreak(line, breakNode, breakOffset);
 
625
            }
 
626
            result.append(data.characters() + position, length - position);
 
627
        }
 
628
        while (breakNode == node)
 
629
            getNextSoftBreak(line, breakNode, breakOffset);
 
630
    }
 
631
    return finishText(result);
 
632
}
 
633
 
 
634
HTMLTextFormControlElement* enclosingTextFormControl(const Position& position)
 
635
{
 
636
    ASSERT(position.isNull() || position.anchorType() == Position::PositionIsOffsetInAnchor
 
637
           || position.containerNode() || !position.anchorNode()->shadowAncestorNode());
 
638
    Node* container = position.containerNode();
 
639
    if (!container)
 
640
        return 0;
 
641
    Node* ancestor = container->shadowAncestorNode();
 
642
    return ancestor != container ? toTextFormControl(ancestor) : 0;
 
643
}
 
644
 
 
645
static const Element* parentHTMLElement(const Element* element)
 
646
{
 
647
    while (element) {
 
648
        element = element->parentElement();
 
649
        if (element && element->isHTMLElement())
 
650
            return element;
 
651
    }
 
652
    return 0;
 
653
}
 
654
 
 
655
String HTMLTextFormControlElement::directionForFormData() const
 
656
{
 
657
    for (const Element* element = this; element; element = parentHTMLElement(element)) {
 
658
        const AtomicString& dirAttributeValue = element->fastGetAttribute(dirAttr);
 
659
        if (dirAttributeValue.isNull())
 
660
            continue;
 
661
 
 
662
        if (equalIgnoringCase(dirAttributeValue, "rtl") || equalIgnoringCase(dirAttributeValue, "ltr"))
 
663
            return dirAttributeValue;
 
664
 
 
665
        if (equalIgnoringCase(dirAttributeValue, "auto")) {
 
666
            bool isAuto;
 
667
            TextDirection textDirection = static_cast<const HTMLElement*>(element)->directionalityIfhasDirAutoAttribute(isAuto);
 
668
            return textDirection == RTL ? "rtl" : "ltr";
 
669
        }
 
670
    }
 
671
 
 
672
    return "ltr";
 
673
}
 
674
 
 
675
void HTMLTextFormControlElement::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
 
676
{
 
677
    MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
 
678
    HTMLFormControlElementWithState::reportMemoryUsage(memoryObjectInfo);
 
679
    info.addMember(m_textAsOfLastFormControlChangeEvent);
 
680
}
 
681
 
 
682
} // namespace Webcore