| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2001 Dirk Mueller (mueller@kde.org) | 4 * (C) 2001 Dirk Mueller (mueller@kde.org) |
| 5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. | 5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. |
| 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) | 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 const AtomicString& attributeValue = fastGetAttribute(placeholderAttr); | 133 const AtomicString& attributeValue = fastGetAttribute(placeholderAttr); |
| 134 return attributeValue.string().find(isNotLineBreak) == notFound; | 134 return attributeValue.string().find(isNotLineBreak) == notFound; |
| 135 } | 135 } |
| 136 | 136 |
| 137 bool HTMLTextFormControlElement::placeholderShouldBeVisible() const | 137 bool HTMLTextFormControlElement::placeholderShouldBeVisible() const |
| 138 { | 138 { |
| 139 return supportsPlaceholder() | 139 return supportsPlaceholder() |
| 140 && isEmptyValue() | 140 && isEmptyValue() |
| 141 && isEmptySuggestedValue() | 141 && isEmptySuggestedValue() |
| 142 && !isPlaceholderEmpty() | 142 && !isPlaceholderEmpty() |
| 143 && (document()->focusedElement() != this || (RenderTheme::theme().should
ShowPlaceholderWhenFocused())) | 143 && (document().focusedElement() != this || (RenderTheme::theme().shouldS
howPlaceholderWhenFocused())) |
| 144 && (!renderer() || renderer()->style()->visibility() == VISIBLE); | 144 && (!renderer() || renderer()->style()->visibility() == VISIBLE); |
| 145 } | 145 } |
| 146 | 146 |
| 147 void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderVal
ueChanged) | 147 void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderVal
ueChanged) |
| 148 { | 148 { |
| 149 if (!supportsPlaceholder()) | 149 if (!supportsPlaceholder()) |
| 150 return; | 150 return; |
| 151 if (!placeholderElement() || placeholderValueChanged) | 151 if (!placeholderElement() || placeholderValueChanged) |
| 152 updatePlaceholderText(); | 152 updatePlaceholderText(); |
| 153 HTMLElement* placeholder = placeholderElement(); | 153 HTMLElement* placeholder = placeholderElement(); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 if (directionString == "forward") | 264 if (directionString == "forward") |
| 265 direction = SelectionHasForwardDirection; | 265 direction = SelectionHasForwardDirection; |
| 266 else if (directionString == "backward") | 266 else if (directionString == "backward") |
| 267 direction = SelectionHasBackwardDirection; | 267 direction = SelectionHasBackwardDirection; |
| 268 | 268 |
| 269 return setSelectionRange(start, end, direction); | 269 return setSelectionRange(start, end, direction); |
| 270 } | 270 } |
| 271 | 271 |
| 272 void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextField
SelectionDirection direction) | 272 void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextField
SelectionDirection direction) |
| 273 { | 273 { |
| 274 document()->updateLayoutIgnorePendingStylesheets(); | 274 document().updateLayoutIgnorePendingStylesheets(); |
| 275 | 275 |
| 276 if (!renderer() || !renderer()->isTextControl()) | 276 if (!renderer() || !renderer()->isTextControl()) |
| 277 return; | 277 return; |
| 278 | 278 |
| 279 end = max(end, 0); | 279 end = max(end, 0); |
| 280 start = min(max(start, 0), end); | 280 start = min(max(start, 0), end); |
| 281 | 281 |
| 282 if (!hasVisibleTextArea(renderer(), innerTextElement())) { | 282 if (!hasVisibleTextArea(renderer(), innerTextElement())) { |
| 283 cacheSelection(start, end, direction); | 283 cacheSelection(start, end, direction); |
| 284 return; | 284 return; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 296 ASSERT(startPosition.deepEquivalent().deprecatedNode()->shadowHost() ==
this | 296 ASSERT(startPosition.deepEquivalent().deprecatedNode()->shadowHost() ==
this |
| 297 && endPosition.deepEquivalent().deprecatedNode()->shadowHost() == th
is); | 297 && endPosition.deepEquivalent().deprecatedNode()->shadowHost() == th
is); |
| 298 } | 298 } |
| 299 VisibleSelection newSelection; | 299 VisibleSelection newSelection; |
| 300 if (direction == SelectionHasBackwardDirection) | 300 if (direction == SelectionHasBackwardDirection) |
| 301 newSelection = VisibleSelection(endPosition, startPosition); | 301 newSelection = VisibleSelection(endPosition, startPosition); |
| 302 else | 302 else |
| 303 newSelection = VisibleSelection(startPosition, endPosition); | 303 newSelection = VisibleSelection(startPosition, endPosition); |
| 304 newSelection.setIsDirectional(direction != SelectionHasNoDirection); | 304 newSelection.setIsDirectional(direction != SelectionHasNoDirection); |
| 305 | 305 |
| 306 if (Frame* frame = document()->frame()) | 306 if (Frame* frame = document().frame()) |
| 307 frame->selection()->setSelection(newSelection); | 307 frame->selection()->setSelection(newSelection); |
| 308 } | 308 } |
| 309 | 309 |
| 310 VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) c
onst | 310 VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) c
onst |
| 311 { | 311 { |
| 312 if (index <= 0) | 312 if (index <= 0) |
| 313 return VisiblePosition(firstPositionInNode(innerTextElement()), DOWNSTRE
AM); | 313 return VisiblePosition(firstPositionInNode(innerTextElement()), DOWNSTRE
AM); |
| 314 RefPtr<Range> range = Range::create(document()); | 314 RefPtr<Range> range = Range::create(&document()); |
| 315 range->selectNodeContents(innerTextElement(), ASSERT_NO_EXCEPTION); | 315 range->selectNodeContents(innerTextElement(), ASSERT_NO_EXCEPTION); |
| 316 CharacterIterator it(range.get()); | 316 CharacterIterator it(range.get()); |
| 317 it.advance(index - 1); | 317 it.advance(index - 1); |
| 318 return VisiblePosition(it.range()->endPosition(), UPSTREAM); | 318 return VisiblePosition(it.range()->endPosition(), UPSTREAM); |
| 319 } | 319 } |
| 320 | 320 |
| 321 int HTMLTextFormControlElement::indexForVisiblePosition(const VisiblePosition& p
os) const | 321 int HTMLTextFormControlElement::indexForVisiblePosition(const VisiblePosition& p
os) const |
| 322 { | 322 { |
| 323 Position indexPosition = pos.deepEquivalent().parentAnchoredEquivalent(); | 323 Position indexPosition = pos.deepEquivalent().parentAnchoredEquivalent(); |
| 324 if (enclosingTextFormControl(indexPosition) != this) | 324 if (enclosingTextFormControl(indexPosition) != this) |
| 325 return 0; | 325 return 0; |
| 326 RefPtr<Range> range = Range::create(indexPosition.document()); | 326 RefPtr<Range> range = Range::create(indexPosition.document()); |
| 327 range->setStart(innerTextElement(), 0, ASSERT_NO_EXCEPTION); | 327 range->setStart(innerTextElement(), 0, ASSERT_NO_EXCEPTION); |
| 328 range->setEnd(indexPosition.containerNode(), indexPosition.offsetInContainer
Node(), ASSERT_NO_EXCEPTION); | 328 range->setEnd(indexPosition.containerNode(), indexPosition.offsetInContainer
Node(), ASSERT_NO_EXCEPTION); |
| 329 return TextIterator::rangeLength(range.get()); | 329 return TextIterator::rangeLength(range.get()); |
| 330 } | 330 } |
| 331 | 331 |
| 332 int HTMLTextFormControlElement::selectionStart() const | 332 int HTMLTextFormControlElement::selectionStart() const |
| 333 { | 333 { |
| 334 if (!isTextFormControl()) | 334 if (!isTextFormControl()) |
| 335 return 0; | 335 return 0; |
| 336 if (document()->focusedElement() != this && hasCachedSelection()) | 336 if (document().focusedElement() != this && hasCachedSelection()) |
| 337 return m_cachedSelectionStart; | 337 return m_cachedSelectionStart; |
| 338 | 338 |
| 339 return computeSelectionStart(); | 339 return computeSelectionStart(); |
| 340 } | 340 } |
| 341 | 341 |
| 342 int HTMLTextFormControlElement::computeSelectionStart() const | 342 int HTMLTextFormControlElement::computeSelectionStart() const |
| 343 { | 343 { |
| 344 ASSERT(isTextFormControl()); | 344 ASSERT(isTextFormControl()); |
| 345 Frame* frame = document()->frame(); | 345 Frame* frame = document().frame(); |
| 346 if (!frame) | 346 if (!frame) |
| 347 return 0; | 347 return 0; |
| 348 | 348 |
| 349 return indexForVisiblePosition(frame->selection()->start()); | 349 return indexForVisiblePosition(frame->selection()->start()); |
| 350 } | 350 } |
| 351 | 351 |
| 352 int HTMLTextFormControlElement::selectionEnd() const | 352 int HTMLTextFormControlElement::selectionEnd() const |
| 353 { | 353 { |
| 354 if (!isTextFormControl()) | 354 if (!isTextFormControl()) |
| 355 return 0; | 355 return 0; |
| 356 if (document()->focusedElement() != this && hasCachedSelection()) | 356 if (document().focusedElement() != this && hasCachedSelection()) |
| 357 return m_cachedSelectionEnd; | 357 return m_cachedSelectionEnd; |
| 358 return computeSelectionEnd(); | 358 return computeSelectionEnd(); |
| 359 } | 359 } |
| 360 | 360 |
| 361 int HTMLTextFormControlElement::computeSelectionEnd() const | 361 int HTMLTextFormControlElement::computeSelectionEnd() const |
| 362 { | 362 { |
| 363 ASSERT(isTextFormControl()); | 363 ASSERT(isTextFormControl()); |
| 364 Frame* frame = document()->frame(); | 364 Frame* frame = document().frame(); |
| 365 if (!frame) | 365 if (!frame) |
| 366 return 0; | 366 return 0; |
| 367 | 367 |
| 368 return indexForVisiblePosition(frame->selection()->end()); | 368 return indexForVisiblePosition(frame->selection()->end()); |
| 369 } | 369 } |
| 370 | 370 |
| 371 static const AtomicString& directionString(TextFieldSelectionDirection direction
) | 371 static const AtomicString& directionString(TextFieldSelectionDirection direction
) |
| 372 { | 372 { |
| 373 DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::Constru
ctFromLiteral)); | 373 DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::Constru
ctFromLiteral)); |
| 374 DEFINE_STATIC_LOCAL(const AtomicString, forward, ("forward", AtomicString::C
onstructFromLiteral)); | 374 DEFINE_STATIC_LOCAL(const AtomicString, forward, ("forward", AtomicString::C
onstructFromLiteral)); |
| 375 DEFINE_STATIC_LOCAL(const AtomicString, backward, ("backward", AtomicString:
:ConstructFromLiteral)); | 375 DEFINE_STATIC_LOCAL(const AtomicString, backward, ("backward", AtomicString:
:ConstructFromLiteral)); |
| 376 | 376 |
| 377 switch (direction) { | 377 switch (direction) { |
| 378 case SelectionHasNoDirection: | 378 case SelectionHasNoDirection: |
| 379 return none; | 379 return none; |
| 380 case SelectionHasForwardDirection: | 380 case SelectionHasForwardDirection: |
| 381 return forward; | 381 return forward; |
| 382 case SelectionHasBackwardDirection: | 382 case SelectionHasBackwardDirection: |
| 383 return backward; | 383 return backward; |
| 384 } | 384 } |
| 385 | 385 |
| 386 ASSERT_NOT_REACHED(); | 386 ASSERT_NOT_REACHED(); |
| 387 return none; | 387 return none; |
| 388 } | 388 } |
| 389 | 389 |
| 390 const AtomicString& HTMLTextFormControlElement::selectionDirection() const | 390 const AtomicString& HTMLTextFormControlElement::selectionDirection() const |
| 391 { | 391 { |
| 392 if (!isTextFormControl()) | 392 if (!isTextFormControl()) |
| 393 return directionString(SelectionHasNoDirection); | 393 return directionString(SelectionHasNoDirection); |
| 394 if (document()->focusedElement() != this && hasCachedSelection()) | 394 if (document().focusedElement() != this && hasCachedSelection()) |
| 395 return directionString(m_cachedSelectionDirection); | 395 return directionString(m_cachedSelectionDirection); |
| 396 | 396 |
| 397 return directionString(computeSelectionDirection()); | 397 return directionString(computeSelectionDirection()); |
| 398 } | 398 } |
| 399 | 399 |
| 400 TextFieldSelectionDirection HTMLTextFormControlElement::computeSelectionDirectio
n() const | 400 TextFieldSelectionDirection HTMLTextFormControlElement::computeSelectionDirectio
n() const |
| 401 { | 401 { |
| 402 ASSERT(isTextFormControl()); | 402 ASSERT(isTextFormControl()); |
| 403 Frame* frame = document()->frame(); | 403 Frame* frame = document().frame(); |
| 404 if (!frame) | 404 if (!frame) |
| 405 return SelectionHasNoDirection; | 405 return SelectionHasNoDirection; |
| 406 | 406 |
| 407 const VisibleSelection& selection = frame->selection()->selection(); | 407 const VisibleSelection& selection = frame->selection()->selection(); |
| 408 return selection.isDirectional() ? (selection.isBaseFirst() ? SelectionHasFo
rwardDirection : SelectionHasBackwardDirection) : SelectionHasNoDirection; | 408 return selection.isDirectional() ? (selection.isBaseFirst() ? SelectionHasFo
rwardDirection : SelectionHasBackwardDirection) : SelectionHasNoDirection; |
| 409 } | 409 } |
| 410 | 410 |
| 411 static inline void setContainerAndOffsetForRange(Node* node, int offset, Node*&
containerNode, int& offsetInContainer) | 411 static inline void setContainerAndOffsetForRange(Node* node, int offset, Node*&
containerNode, int& offsetInContainer) |
| 412 { | 412 { |
| 413 if (node->isTextNode()) { | 413 if (node->isTextNode()) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 426 | 426 |
| 427 int start = m_cachedSelectionStart; | 427 int start = m_cachedSelectionStart; |
| 428 int end = m_cachedSelectionEnd; | 428 int end = m_cachedSelectionEnd; |
| 429 | 429 |
| 430 ASSERT(start <= end); | 430 ASSERT(start <= end); |
| 431 HTMLElement* innerText = innerTextElement(); | 431 HTMLElement* innerText = innerTextElement(); |
| 432 if (!innerText) | 432 if (!innerText) |
| 433 return 0; | 433 return 0; |
| 434 | 434 |
| 435 if (!innerText->firstChild()) | 435 if (!innerText->firstChild()) |
| 436 return Range::create(document(), innerText, 0, innerText, 0); | 436 return Range::create(&document(), innerText, 0, innerText, 0); |
| 437 | 437 |
| 438 int offset = 0; | 438 int offset = 0; |
| 439 Node* startNode = 0; | 439 Node* startNode = 0; |
| 440 Node* endNode = 0; | 440 Node* endNode = 0; |
| 441 for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(
node, innerText)) { | 441 for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(
node, innerText)) { |
| 442 ASSERT(!node->firstChild()); | 442 ASSERT(!node->firstChild()); |
| 443 ASSERT(node->isTextNode() || node->hasTagName(brTag)); | 443 ASSERT(node->isTextNode() || node->hasTagName(brTag)); |
| 444 int length = node->isTextNode() ? lastOffsetInNode(node) : 1; | 444 int length = node->isTextNode() ? lastOffsetInNode(node) : 1; |
| 445 | 445 |
| 446 if (offset <= start && start <= offset + length) | 446 if (offset <= start && start <= offset + length) |
| 447 setContainerAndOffsetForRange(node, start - offset, startNode, start
); | 447 setContainerAndOffsetForRange(node, start - offset, startNode, start
); |
| 448 | 448 |
| 449 if (offset <= end && end <= offset + length) { | 449 if (offset <= end && end <= offset + length) { |
| 450 setContainerAndOffsetForRange(node, end - offset, endNode, end); | 450 setContainerAndOffsetForRange(node, end - offset, endNode, end); |
| 451 break; | 451 break; |
| 452 } | 452 } |
| 453 | 453 |
| 454 offset += length; | 454 offset += length; |
| 455 } | 455 } |
| 456 | 456 |
| 457 if (!startNode || !endNode) | 457 if (!startNode || !endNode) |
| 458 return 0; | 458 return 0; |
| 459 | 459 |
| 460 return Range::create(document(), startNode, start, endNode, end); | 460 return Range::create(&document(), startNode, start, endNode, end); |
| 461 } | 461 } |
| 462 | 462 |
| 463 void HTMLTextFormControlElement::restoreCachedSelection() | 463 void HTMLTextFormControlElement::restoreCachedSelection() |
| 464 { | 464 { |
| 465 setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, m_cachedSele
ctionDirection); | 465 setSelectionRange(m_cachedSelectionStart, m_cachedSelectionEnd, m_cachedSele
ctionDirection); |
| 466 } | 466 } |
| 467 | 467 |
| 468 void HTMLTextFormControlElement::selectionChanged(bool userTriggered) | 468 void HTMLTextFormControlElement::selectionChanged(bool userTriggered) |
| 469 { | 469 { |
| 470 if (!renderer() || !isTextFormControl()) | 470 if (!renderer() || !isTextFormControl()) |
| 471 return; | 471 return; |
| 472 | 472 |
| 473 // selectionStart() or selectionEnd() will return cached selection when this
node doesn't have focus | 473 // selectionStart() or selectionEnd() will return cached selection when this
node doesn't have focus |
| 474 cacheSelection(computeSelectionStart(), computeSelectionEnd(), computeSelect
ionDirection()); | 474 cacheSelection(computeSelectionStart(), computeSelectionEnd(), computeSelect
ionDirection()); |
| 475 | 475 |
| 476 if (Frame* frame = document()->frame()) { | 476 if (Frame* frame = document().frame()) { |
| 477 if (frame->selection()->isRange() && userTriggered) | 477 if (frame->selection()->isRange() && userTriggered) |
| 478 dispatchEvent(Event::createBubble(eventNames().selectEvent)); | 478 dispatchEvent(Event::createBubble(eventNames().selectEvent)); |
| 479 } | 479 } |
| 480 } | 480 } |
| 481 | 481 |
| 482 void HTMLTextFormControlElement::parseAttribute(const QualifiedName& name, const
AtomicString& value) | 482 void HTMLTextFormControlElement::parseAttribute(const QualifiedName& name, const
AtomicString& value) |
| 483 { | 483 { |
| 484 if (name == placeholderAttr) { | 484 if (name == placeholderAttr) { |
| 485 updatePlaceholderVisibility(true); | 485 updatePlaceholderVisibility(true); |
| 486 UseCounter::count(document(), UseCounter::PlaceholderAttribute); | 486 UseCounter::count(&document(), UseCounter::PlaceholderAttribute); |
| 487 } else | 487 } else |
| 488 HTMLFormControlElementWithState::parseAttribute(name, value); | 488 HTMLFormControlElementWithState::parseAttribute(name, value); |
| 489 } | 489 } |
| 490 | 490 |
| 491 bool HTMLTextFormControlElement::lastChangeWasUserEdit() const | 491 bool HTMLTextFormControlElement::lastChangeWasUserEdit() const |
| 492 { | 492 { |
| 493 if (!isTextFormControl()) | 493 if (!isTextFormControl()) |
| 494 return false; | 494 return false; |
| 495 return m_lastChangeWasUserEdit; | 495 return m_lastChangeWasUserEdit; |
| 496 } | 496 } |
| 497 | 497 |
| 498 void HTMLTextFormControlElement::setInnerTextValue(const String& value) | 498 void HTMLTextFormControlElement::setInnerTextValue(const String& value) |
| 499 { | 499 { |
| 500 if (!isTextFormControl()) | 500 if (!isTextFormControl()) |
| 501 return; | 501 return; |
| 502 | 502 |
| 503 bool textIsChanged = value != innerTextValue(); | 503 bool textIsChanged = value != innerTextValue(); |
| 504 if (textIsChanged || !innerTextElement()->hasChildNodes()) { | 504 if (textIsChanged || !innerTextElement()->hasChildNodes()) { |
| 505 if (textIsChanged && document() && renderer()) { | 505 if (textIsChanged && renderer()) { |
| 506 if (AXObjectCache* cache = document()->existingAXObjectCache()) | 506 if (AXObjectCache* cache = document().existingAXObjectCache()) |
| 507 cache->postNotification(this, AXObjectCache::AXValueChanged, fal
se); | 507 cache->postNotification(this, AXObjectCache::AXValueChanged, fal
se); |
| 508 } | 508 } |
| 509 innerTextElement()->setInnerText(value, ASSERT_NO_EXCEPTION); | 509 innerTextElement()->setInnerText(value, ASSERT_NO_EXCEPTION); |
| 510 | 510 |
| 511 if (value.endsWith('\n') || value.endsWith('\r')) | 511 if (value.endsWith('\n') || value.endsWith('\r')) |
| 512 innerTextElement()->appendChild(HTMLBRElement::create(document())); | 512 innerTextElement()->appendChild(HTMLBRElement::create(&document())); |
| 513 } | 513 } |
| 514 | 514 |
| 515 setFormControlValueMatchesRenderer(true); | 515 setFormControlValueMatchesRenderer(true); |
| 516 } | 516 } |
| 517 | 517 |
| 518 static String finishText(StringBuilder& result) | 518 static String finishText(StringBuilder& result) |
| 519 { | 519 { |
| 520 // Remove one trailing newline; there's always one that's collapsed out by r
endering. | 520 // Remove one trailing newline; there's always one that's collapsed out by r
endering. |
| 521 size_t size = result.length(); | 521 size_t size = result.length(); |
| 522 if (size && result[size - 1] == '\n') | 522 if (size && result[size - 1] == '\n') |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 638 bool isAuto; | 638 bool isAuto; |
| 639 TextDirection textDirection = static_cast<const HTMLElement*>(elemen
t)->directionalityIfhasDirAutoAttribute(isAuto); | 639 TextDirection textDirection = static_cast<const HTMLElement*>(elemen
t)->directionalityIfhasDirAutoAttribute(isAuto); |
| 640 return textDirection == RTL ? "rtl" : "ltr"; | 640 return textDirection == RTL ? "rtl" : "ltr"; |
| 641 } | 641 } |
| 642 } | 642 } |
| 643 | 643 |
| 644 return "ltr"; | 644 return "ltr"; |
| 645 } | 645 } |
| 646 | 646 |
| 647 } // namespace Webcore | 647 } // namespace Webcore |
| OLD | NEW |