aee62ce85368839dfb0ef25ea434402ae2ca456d
[WebKit-https.git] / WebCore / rendering / RenderTextField.cpp
1 /**
2  * Copyright (C) 2006 Apple Computer, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  */
20
21 #include "config.h"
22 #include "RenderTextField.h"
23
24 #include "Document.h"
25 #include "EventNames.h"
26 #include "Frame.h"
27 #include "HTMLInputElement.h"
28 #include "HTMLNames.h"
29 #include "HTMLTextFieldInnerElement.h"
30 #include "RenderText.h"
31 #include "SelectionController.h"
32 #include "TextIterator.h"
33 #include "VisiblePosition.h"
34 #include "dom2_eventsimpl.h"
35 #include <algorithm>
36
37 namespace WebCore {
38
39 using namespace EventNames;
40 using namespace HTMLNames;
41 using namespace std;
42
43 RenderTextField::RenderTextField(Node* node)
44     : RenderBlock(node), m_dirty(false)
45 {
46 }
47
48 RenderTextField::~RenderTextField()
49 {
50     // The renderer for the div has already been destroyed by destroyLeftoverChildren
51     if (m_div)
52         m_div->detach();
53 }
54
55 void RenderTextField::setStyle(RenderStyle* style)
56 {
57     RenderBlock::setStyle(style);
58     if (m_div) {
59         RenderBlock* divRenderer = static_cast<RenderBlock*>(m_div->renderer());
60         RenderStyle* divStyle = createDivStyle(style);
61         divRenderer->setStyle(divStyle);
62         for (Node *n = m_div->firstChild(); n; n = n->traverseNextNode(m_div.get()))
63             if (n->renderer())
64                 n->renderer()->setStyle(divStyle);
65     }
66     setReplaced(isInline());
67 }
68
69 RenderStyle* RenderTextField::createDivStyle(RenderStyle* startStyle)
70 {
71     RenderStyle* divStyle = new (renderArena()) RenderStyle();
72     divStyle->inheritFrom(startStyle);
73     divStyle->setDisplay(BLOCK);
74     divStyle->setOverflow(OHIDDEN);
75     divStyle->setWhiteSpace(NOWRAP);
76
77     if (element()->hasTagName(inputTag))
78         divStyle->setUserModify(static_cast<HTMLGenericFormElement *>(element())->readOnly() ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY);
79
80     // We're adding this extra pixel of padding to match WinIE.
81     divStyle->setPaddingLeft(Length(1, Fixed));
82     divStyle->setPaddingRight(Length(1, Fixed));
83
84     return divStyle;
85 }
86
87 void RenderTextField::updateFromElement()
88 {
89     if (element()->hasTagName(inputTag)) {
90         HTMLInputElement* input = static_cast<HTMLInputElement*>(element());
91         String value = input->value().copy();
92         if (value.isNull())
93             value = "";
94         unsigned ml = input->maxLength();
95         bool valueHasChanged = false;
96         if (value.length() > ml) {
97             value.truncate(ml);
98             valueHasChanged = true;
99         }
100             
101         if (!m_div) {
102             // Create the div and give it a parent, renderer, and style
103             m_div = new HTMLTextFieldInnerElement(document(), node());
104             RenderBlock* divRenderer = new (renderArena()) RenderBlock(m_div.get());
105             m_div->setRenderer(divRenderer);
106             m_div->setAttached();
107             m_div->setInDocument(true);
108             
109             RenderStyle* divStyle = createDivStyle(style());
110             divRenderer->setStyle(divStyle); 
111             
112             // Add div to Render tree
113             RenderBlock::addChild(divRenderer);
114         }
115
116         m_div->renderer()->style()->setUserModify(static_cast<HTMLGenericFormElement *>(element())->readOnly() ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY);
117         
118         if (!input->valueMatchesRenderer()) {
119             String oldText = this->text();
120             value.replace(QChar('\\'), backslashAsCurrencySymbol());
121             if (value != oldText) {
122                 ExceptionCode ec = 0;
123                 m_div->setInnerText(value, ec);
124                 setEdited(false);
125             }
126             input->setValueMatchesRenderer();
127         }
128         
129         if (valueHasChanged)
130             input->setValueFromRenderer(value);
131     }
132 }
133
134 int RenderTextField::selectionStart()
135 {
136     return indexForVisiblePosition(document()->frame()->selection().start());        
137 }
138
139 int RenderTextField::selectionEnd()
140 {
141     return indexForVisiblePosition(document()->frame()->selection().end());        
142 }
143
144 void RenderTextField::setSelectionStart(int start)
145 {
146     setSelectionRange(start, max(start, selectionEnd()));
147 }
148  
149 void RenderTextField::setSelectionEnd(int end)
150 {
151     setSelectionRange(min(end, selectionStart()), end);
152 }
153     
154 void RenderTextField::select()
155 {
156     setSelectionRange(0, text().length());
157 }
158
159 void RenderTextField::setSelectionRange(int start, int end)
160 {
161     end = max(end, 0);
162     start = min(max(start, 0), end);
163     
164     document()->updateLayout();
165     
166     VisiblePosition startPosition = visiblePositionForIndex(start);
167     VisiblePosition endPosition = visiblePositionForIndex(end);
168     
169     ASSERT(startPosition.isNotNull() && endPosition.isNotNull());
170     ASSERT(startPosition.deepEquivalent().node()->shadowAncestorNode() == node() && endPosition.deepEquivalent().node()->shadowAncestorNode() == node());
171
172     SelectionController sel = SelectionController(startPosition, endPosition);
173     document()->frame()->setSelection(sel, false);
174 }
175
176 VisiblePosition RenderTextField::visiblePositionForIndex(int index)
177 {    
178     if (index <= 0)
179         return VisiblePosition(m_div.get(), 0, DOWNSTREAM);
180     ExceptionCode ec = 0;
181     RefPtr<Range> range = new Range(document());
182     range->selectNodeContents(m_div.get(), ec);
183     CharacterIterator it(range.get());
184     it.advance(index - 1);
185     return VisiblePosition(it.range()->endContainer(ec), it.range()->endOffset(ec), UPSTREAM);
186 }
187
188 int RenderTextField::indexForVisiblePosition(const VisiblePosition& pos)
189 {
190     Position indexPosition = pos.deepEquivalent();
191     if (!indexPosition.node() || indexPosition.node()->rootEditableElement() != m_div)
192         return 0;
193     ExceptionCode ec = 0;
194     RefPtr<Range> range = new Range(document());
195     range->setStart(m_div.get(), 0, ec);
196     range->setEnd(indexPosition.node(), indexPosition.offset(), ec);
197     return TextIterator::rangeLength(range.get());
198 }
199
200 void RenderTextField::subtreeHasChanged()
201 {
202     HTMLInputElement* input = static_cast<HTMLInputElement*>(element());
203     if (input) {
204         input->setValueFromRenderer(text());
205         setEdited(true);
206     }
207 }
208
209 String RenderTextField::text()
210 {
211     if (m_div)
212         return m_div->textContent();
213     return String();
214 }
215
216 void RenderTextField::calcMinMaxWidth()
217 {
218     m_minWidth = 0;
219     m_maxWidth = 0;
220
221     if (style()->width().isFixed() && style()->width().value() > 0)
222         m_minWidth = m_maxWidth = calcContentBoxWidth(style()->width().value());
223     else {
224         // Figure out how big a text field needs to be for a given number of characters
225         // (using "0" as the nominal character).
226         int size = static_cast<HTMLInputElement*>(element())->size();
227         if (size <= 0)
228             size = 20;
229
230         QChar ch[1];
231         ch[0] = '0';
232         int sizeWidth = (int)ceilf(style()->font().floatWidth(ch, 1, 0, 1, 0, 0) * size);
233         m_maxWidth = sizeWidth;
234     }
235     
236     if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
237         m_maxWidth = max(m_maxWidth, calcContentBoxWidth(style()->minWidth().value()));
238         m_minWidth = max(m_minWidth, calcContentBoxWidth(style()->minWidth().value()));
239     } else
240         m_minWidth = m_maxWidth;
241     
242     if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
243         m_maxWidth = min(m_maxWidth, calcContentBoxWidth(style()->maxWidth().value()));
244         m_minWidth = min(m_minWidth, calcContentBoxWidth(style()->maxWidth().value()));
245     }
246
247     int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight() + m_div->renderer()->paddingLeft() + m_div->renderer()->paddingRight();
248     m_minWidth += toAdd;
249     m_maxWidth += toAdd;
250
251     setMinMaxKnown();    
252 }
253
254 void RenderTextField::forwardEvent(Event* evt)
255 {
256     if (evt->type() == blurEvent) {
257         RenderObject* innerRenderer = m_div->renderer();
258         if (innerRenderer) {
259             RenderLayer* innerLayer = innerRenderer->layer();
260             if (innerLayer)
261                 innerLayer->scrollToOffset(style()->direction() == RTL ? innerLayer->scrollWidth() : 0, 0);
262         }
263     } else
264         m_div->defaultEventHandler(evt);
265 }
266
267 }