Changeset 34822 in webkit


Ignore:
Timestamp:
Jun 26, 2008 8:24:51 PM (16 years ago)
Author:
mitz@apple.com
Message:

WebCore:

Reviewed by Darin Adler.

Test: editing/selection/find-in-text-control.html

  • WebCore.base.exp: Updated the TextIterator constructor signature.
  • editing/TextIterator.cpp: (WebCore::TextIterator::TextIterator): Added an enterTextControls boolean parameter that determines whether the iterator should visit text inside text areas and text fields. Added code to initialize the m_inShadowContent member variable based on whether the range is in shadow content. (WebCore::TextIterator::advance): Added code to step out of shadow content. (WebCore::TextIterator::handleReplacedElement): Added code to enter text controls if desired. (WebCore::CharacterIterator::CharacterIterator): Added an enterTextControls boolean parameter that determines whether the iterator should visit text inside text areas and text fields. This is passed to the TextIterator constructor. (WebCore::findPlainText): Changed to use a CharacterIterator that visits text controls.
  • editing/TextIterator.h: Added member variables to track whether the current node is in a shadow tree and whether the iterator should visit text controls.
  • page/Frame.cpp: (WebCore::Frame::findString): Changed to find inside text controls. (WebCore::Frame::markAllMatchesForText): Ditto.
  • rendering/RenderTextControl.cpp: (WebCore::RenderTextControl::innerTextElement): Added.
  • rendering/RenderTextControl.h: Added innerTextElement(), a private accessor method that is accessible to TextIterator through class friendship.

LayoutTests:

Reviewed by Darin Adler.

  • editing/selection/find-in-text-control-expected.txt: Added.
  • editing/selection/find-in-text-control.html: Added.
Location:
trunk
Files:
2 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r34816 r34822  
     12008-06-26  Dan Bernstein  <mitz@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        - test for <rdar://problem/3099526> Find command doesn't search form input controls (textareas and text fields)
     6          http://bugs.webkit.org/show_bug.cgi?id=7023
     7
     8        * editing/selection/find-in-text-control-expected.txt: Added.
     9        * editing/selection/find-in-text-control.html: Added.
     10
    1112008-06-26  Beth Dakin  <bdakin@apple.com>
    212
  • trunk/WebCore/ChangeLog

    r34820 r34822  
     12008-06-26  Dan Bernstein  <mitz@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        - fix <rdar://problem/3099526> Find command doesn't search form input controls (textareas and text fields)
     6          http://bugs.webkit.org/show_bug.cgi?id=7023
     7
     8        Test: editing/selection/find-in-text-control.html
     9
     10        * WebCore.base.exp: Updated the TextIterator constructor signature.
     11
     12        * editing/TextIterator.cpp:
     13        (WebCore::TextIterator::TextIterator): Added an enterTextControls
     14        boolean parameter that determines whether the iterator should visit text
     15        inside text areas and text fields. Added code to initialize the
     16        m_inShadowContent member variable based on whether the range is in
     17        shadow content.
     18        (WebCore::TextIterator::advance): Added code to step out of shadow
     19        content.
     20        (WebCore::TextIterator::handleReplacedElement): Added code to enter
     21        text controls if desired.
     22        (WebCore::CharacterIterator::CharacterIterator): Added an
     23        enterTextControls boolean parameter that determines whether the iterator
     24        should visit text inside text areas and text fields. This is passed to
     25        the TextIterator constructor.
     26        (WebCore::findPlainText): Changed to use a CharacterIterator that
     27        visits text controls.
     28
     29        * editing/TextIterator.h: Added member variables to track whether the
     30        current node is in a shadow tree and whether the iterator should visit
     31        text controls.
     32
     33        * page/Frame.cpp:
     34        (WebCore::Frame::findString): Changed to find inside text controls.
     35        (WebCore::Frame::markAllMatchesForText): Ditto.
     36
     37        * rendering/RenderTextControl.cpp:
     38        (WebCore::RenderTextControl::innerTextElement): Added.
     39        * rendering/RenderTextControl.h: Added innerTextElement(), a private
     40        accessor method that is accessible to TextIterator through class
     41        friendship.
     42
    1432008-06-26  Darin Adler  <darin@apple.com>
    244
  • trunk/WebCore/WebCore.base.exp

    r34589 r34822  
    256256__ZN7WebCore12TextIterator26rangeFromLocationAndLengthEPNS_7ElementEiib
    257257__ZN7WebCore12TextIterator7advanceEv
    258 __ZN7WebCore12TextIteratorC1EPKNS_5RangeEb
     258__ZN7WebCore12TextIteratorC1EPKNS_5RangeEbb
    259259__ZN7WebCore12applyCommandEN3WTF10PassRefPtrINS_11EditCommandEEE
    260260__ZN7WebCore12cacheStorageEv
  • trunk/WebCore/editing/TextIterator.cpp

    r34596 r34822  
    3838#include "RenderTableCell.h"
    3939#include "RenderTableRow.h"
     40#include "RenderTextControl.h"
    4041#include "visible_units.h"
    4142
     
    7374// --------
    7475
    75 TextIterator::TextIterator() : m_startContainer(0), m_startOffset(0), m_endContainer(0), m_endOffset(0), m_positionNode(0), m_lastCharacter(0)
    76 {
    77 }
    78 
    79 TextIterator::TextIterator(const Range* r, bool emitCharactersBetweenAllVisiblePositions)
    80     : m_startContainer(0)
     76TextIterator::TextIterator()
     77    : m_startContainer(0)
     78    , m_startOffset(0)
     79    , m_endContainer(0)
     80    , m_endOffset(0)
     81    , m_positionNode(0)
     82    , m_lastCharacter(0)
     83    , m_emitCharactersBetweenAllVisiblePositions(false)
     84    , m_enterTextControls(false)
     85{
     86}
     87
     88TextIterator::TextIterator(const Range* r, bool emitCharactersBetweenAllVisiblePositions, bool enterTextControls)
     89    : m_inShadowContent(false)
     90    , m_startContainer(0)
    8191    , m_startOffset(0)
    8292    , m_endContainer(0)
     
    8494    , m_positionNode(0)
    8595    , m_emitCharactersBetweenAllVisiblePositions(emitCharactersBetweenAllVisiblePositions)
     96    , m_enterTextControls(enterTextControls)
    8697{
    8798    if (!r)
     
    107118    m_endContainer = endContainer;
    108119    m_endOffset = endOffset;
    109    
     120
     121    for (Node* n = startContainer; n; n = n->parentNode()) {
     122        if (n->isShadowNode()) {
     123            m_inShadowContent = true;
     124            break;
     125        }
     126    }
     127
    110128    // set up the current node for processing
    111129    m_node = r->firstNode();
     
    202220            if (!next) {
    203221                bool pastEnd = m_node->traverseNextNode() == m_pastEndNode;
    204                 while (!next && m_node->parentNode()) {
    205                     if (pastEnd && m_node->parentNode() == m_endContainer || m_endContainer->isDescendantOf(m_node->parentNode()))
     222                Node* parentNode = m_node->parentNode();
     223                if (!parentNode && m_inShadowContent) {
     224                    m_inShadowContent = false;
     225                    parentNode = m_node->shadowParentNode();
     226                }
     227                while (!next && parentNode) {
     228                    if (pastEnd && parentNode == m_endContainer || m_endContainer->isDescendantOf(parentNode))
    206229                        return;
    207230                    bool haveRenderer = m_node->renderer();
    208                     m_node = m_node->parentNode();
     231                    m_node = parentNode;
     232                    parentNode = m_node->parentNode();
     233                    if (!parentNode && m_inShadowContent) {
     234                        m_inShadowContent = false;
     235                        parentNode = m_node->shadowParentNode();
     236                    }
    209237                    if (haveRenderer)
    210238                        exitNode();
     
    350378bool TextIterator::handleReplacedElement()
    351379{
    352     if (m_node->renderer()->style()->visibility() != VISIBLE)
     380    RenderObject* renderer = m_node->renderer();
     381    if (renderer->style()->visibility() != VISIBLE)
    353382        return false;
    354383
     
    358387    }
    359388
     389    if (m_enterTextControls && (renderer->isTextArea() || renderer->isTextField())) {
     390        m_node = static_cast<RenderTextControl*>(renderer)->innerTextElement();
     391        m_offset = 0;
     392        m_inShadowContent = true;
     393        return false;
     394    }
     395
    360396    m_haveEmitted = true;
    361    
     397
    362398    if (m_emitCharactersBetweenAllVisiblePositions) {
    363399        // We want replaced elements to behave like punctuation for boundary
     
    367403        return true;
    368404    }
    369    
     405
    370406    m_positionNode = m_node->parentNode();
    371407    m_positionOffsetBaseNode = m_node;
     
    895931
    896932CharacterIterator::CharacterIterator()
    897     : m_offset(0), m_runOffset(0), m_atBreak(true)
    898 {
    899 }
    900 
    901 CharacterIterator::CharacterIterator(const Range *r, bool emitCharactersBetweenAllVisiblePositions)
    902     : m_offset(0), m_runOffset(0), m_atBreak(true), m_textIterator(r, emitCharactersBetweenAllVisiblePositions)
     933    : m_offset(0)
     934    , m_runOffset(0)
     935    , m_atBreak(true)
     936{
     937}
     938
     939CharacterIterator::CharacterIterator(const Range *r, bool emitCharactersBetweenAllVisiblePositions, bool enterTextControls)
     940    : m_offset(0)
     941    , m_runOffset(0)
     942    , m_atBreak(true)
     943    , m_textIterator(r, emitCharactersBetweenAllVisiblePositions, enterTextControls)
    903944{
    904945    while (!atEnd() && m_textIterator.length() == 0)
     
    13521393    {
    13531394        CircularSearchBuffer searchBuffer(target, caseSensitive);
    1354         CharacterIterator it(range);
     1395        CharacterIterator it(range, false, true);
    13551396        for (;;) {
    13561397            if (searchBuffer.isMatch()) {
     
    13771418
    13781419    if (matchLength) {
    1379         CharacterIterator it(range);
     1420        CharacterIterator it(range, false, true);
    13801421        it.advance(matchStart);
    13811422        result->setStart(it.range()->startContainer(ec), it.range()->startOffset(ec), ec);
  • trunk/WebCore/editing/TextIterator.h

    r34780 r34822  
    5757public:
    5858    TextIterator();
    59     explicit TextIterator(const Range*, bool emitCharactersBetweenAllVisiblePositions = false);
     59    explicit TextIterator(const Range*, bool emitCharactersBetweenAllVisiblePositions = false, bool enterTextControls = false);
    6060   
    6161    bool atEnd() const { return !m_positionNode; }
     
    8989    bool m_handledNode;
    9090    bool m_handledChildren;
     91    bool m_inShadowContent;
    9192   
    9293    // The range.
     
    130131    // moveParagraphs to not clone/destroy moved content.
    131132    bool m_emitCharactersBetweenAllVisiblePositions;
     133    bool m_enterTextControls;
    132134};
    133135
     
    192194public:
    193195    CharacterIterator();
    194     explicit CharacterIterator(const Range* r, bool emitCharactersBetweenAllVisiblePositions = false);
     196    explicit CharacterIterator(const Range* r, bool emitCharactersBetweenAllVisiblePositions = false, bool enterTextControls = false);
    195197   
    196198    void advance(int numCharacters);
  • trunk/WebCore/page/Frame.cpp

    r34627 r34822  
    15931593    Selection selection = this->selection()->selection();
    15941594    Node* selectionBaseNode = selection.base().node();
    1595    
    1596     // FIXME 3099526: We don't search in the shadow trees (e.g. text fields and textareas), though we'd like to
    1597     // someday. If we don't explicitly skip them here, we'll miss hits in the regular content.
     1595
     1596    if (forward)
     1597        setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd());
     1598    else
     1599        setEnd(searchRange.get(), startInSelection ? selection.visibleEnd() : selection.visibleStart());
     1600
    15981601    bool selectionIsInMainContent = selectionBaseNode && !isInShadowTree(selectionBaseNode);
    1599 
    1600     if (selectionIsInMainContent) {
     1602    Node* shadowTreeRoot = 0;
     1603    if (!selectionIsInMainContent) {
     1604        shadowTreeRoot = selectionBaseNode;
     1605        while (shadowTreeRoot && !shadowTreeRoot->isShadowNode())
     1606            shadowTreeRoot = shadowTreeRoot->parentNode();
     1607    }
     1608
     1609    if (shadowTreeRoot) {
     1610        ExceptionCode ec = 0;
    16011611        if (forward)
    1602             setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd());
     1612            searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
    16031613        else
    1604             setEnd(searchRange.get(), startInSelection ? selection.visibleEnd() : selection.visibleStart());
    1605     }
     1614            searchRange->setStart(shadowTreeRoot, 0, ec);
     1615    }
     1616
    16061617    RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
    16071618    // If we started in the selection and the found range exactly matches the existing selection, find again.
    16081619    // Build a selection with the found range to remove collapsed whitespace.
    16091620    // Compare ranges instead of selection objects to ignore the way that the current selection was made.
    1610     if (startInSelection && selectionIsInMainContent && *Selection(resultRange.get()).toRange() == *selection.toRange()) {
     1621    if (startInSelection && *Selection(resultRange.get()).toRange() == *selection.toRange()) {
    16111622        searchRange = rangeOfContents(document());
    16121623        if (forward)
     
    16141625        else
    16151626            setEnd(searchRange.get(), selection.visibleStart());
     1627
     1628        if (shadowTreeRoot) {
     1629            ExceptionCode ec = 0;
     1630            if (forward)
     1631                searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
     1632            else
     1633                searchRange->setStart(shadowTreeRoot, 0, ec);
     1634        }
     1635
    16161636        resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
    16171637    }
    16181638   
    1619     int exception = 0;
    1620    
     1639    ExceptionCode exception = 0;
     1640
     1641    // If nothing was found in the shadow tree, search in main content following the shadow tree.
     1642    if (resultRange->collapsed(exception) && shadowTreeRoot) {
     1643        searchRange = rangeOfContents(document());
     1644        if (forward)
     1645            searchRange->setStartAfter(shadowTreeRoot->shadowParentNode(), exception);
     1646        else
     1647            searchRange->setEndBefore(shadowTreeRoot->shadowParentNode(), exception);
     1648
     1649        resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
     1650    }
     1651
    16211652    // If we didn't find anything and we're wrapping, search again in the entire document (this will
    16221653    // redundantly re-search the area already searched in some cases).
     
    16441675    RefPtr<Range> searchRange(rangeOfContents(document()));
    16451676   
    1646     int exception = 0;
     1677    ExceptionCode exception = 0;
    16471678    unsigned matchCount = 0;
    16481679    do {
    16491680        RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
    1650         if (resultRange->collapsed(exception))
    1651             break;
     1681        if (resultRange->collapsed(exception)) {
     1682            if (!isInShadowTree(resultRange->startContainer()))
     1683                break;
     1684
     1685            searchRange = rangeOfContents(document());
     1686            searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), exception);
     1687            continue;
     1688        }
    16521689       
    16531690        // A non-collapsed result range can in some funky whitespace cases still not
     
    16661703       
    16671704        setStart(searchRange.get(), newStart);
     1705        if (searchRange->collapsed(exception) && isInShadowTree(searchRange->startContainer())) {
     1706            Node* shadowTreeRoot = searchRange->startContainer();
     1707            while (shadowTreeRoot && !shadowTreeRoot->isShadowNode())
     1708                shadowTreeRoot = shadowTreeRoot->parentNode();
     1709            if (shadowTreeRoot)
     1710                searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), exception);
     1711        }
    16681712    } while (true);
    16691713   
  • trunk/WebCore/rendering/RenderTextControl.cpp

    r34693 r34822  
    577577
    578578    return String::adopt(result);
     579}
     580
     581HTMLElement* RenderTextControl::innerTextElement() const
     582{
     583    return m_innerText.get();
    579584}
    580585
  • trunk/WebCore/rendering/RenderTextControl.h

    r34693 r34822  
    143143    String finishText(Vector<UChar>&) const;
    144144
     145    friend class TextIterator;
     146    HTMLElement* innerTextElement() const;
     147
    145148    RefPtr<HTMLTextFieldInnerElement> m_innerBlock;
    146149    RefPtr<HTMLTextFieldInnerTextElement> m_innerText;
Note: See TracChangeset for help on using the changeset viewer.