Reviewed by Anders.
[WebKit-https.git] / WebCore / rendering / RenderText.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * (C) 1999 Lars Knoll (knoll@kde.org)
5  * (C) 2000 Dirk Mueller (mueller@kde.org)
6  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
7  * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  *
24  */
25
26 #include "config.h"
27 #include "RenderText.h"
28
29 #include "DeprecatedString.h"
30 #include "InlineTextBox.h"
31 #include "Pen.h"
32 #include "Range.h"
33 #include "RenderArena.h"
34 #include "RenderBlock.h"
35 #include "break_lines.h"
36 #include <unicode/ubrk.h>
37 #include <wtf/AlwaysInline.h>
38
39 using namespace std;
40
41 namespace WebCore {
42
43 UBreakIterator* characterBreakIterator(const StringImpl* i)
44 {
45     if (!i)
46         return 0;
47
48     // The locale is currently ignored when determining character cluster breaks.
49     // This may change in the future, according to Deborah Goldsmith.
50     static bool createdIterator = false;
51     static UBreakIterator* iterator;
52     UErrorCode status;
53     if (!createdIterator) {
54         status = U_ZERO_ERROR;
55         iterator = ubrk_open(UBRK_CHARACTER, "en_us", 0, 0, &status);
56         createdIterator = true;
57     }
58     if (!iterator)
59         return 0;
60
61     status = U_ZERO_ERROR;
62     ubrk_setText(iterator, reinterpret_cast<const UChar*>(i->characters()), i->length(), &status);
63     if (status != U_ZERO_ERROR)
64         return 0;
65
66     return iterator;
67 }
68
69 int RenderText::previousOffset(int current) const
70 {
71     UBreakIterator* iterator = characterBreakIterator(str.get());
72     if (!iterator)
73         return current - 1;
74
75     long result = ubrk_preceding(iterator, current);
76     if (result == UBRK_DONE)
77         result = current - 1;
78
79     return result;
80 }
81
82 int RenderText::nextOffset(int current) const
83 {
84     UBreakIterator* iterator = characterBreakIterator(str.get());
85     if (!iterator)
86         return current + 1;
87     
88     long result = ubrk_following(iterator, current);
89     if (result == UBRK_DONE)
90         result = current + 1;
91
92     return result;
93 }
94
95 RenderText::RenderText(Node* node, StringImpl *_str)
96      : RenderObject(node), str(_str), m_firstTextBox(0), m_lastTextBox(0)
97      , m_minWidth(-1), m_maxWidth(-1), m_selectionState(SelectionNone)
98      , m_linesDirty(false), m_containsReversedText(false)
99      , m_allAsciiChecked(false), m_allAscii(false)
100      , m_monospaceCharacterWidth(0)
101 {
102     setRenderText();
103     if (str)
104         str = str->replace('\\', backslashAsCurrencySymbol());
105     ASSERT(!str || !str->length() || str->characters());
106 }
107
108 void RenderText::setStyle(RenderStyle *_style)
109 {
110     if ( style() != _style ) {
111         bool needToTransformText = (!style() && _style->textTransform() != TTNONE) ||
112                                    (style() && style()->textTransform() != _style->textTransform());
113
114         bool needToSecureText = (!style() && _style->textSecurity() != TSNONE);
115
116         RenderObject::setStyle( _style );
117
118         if (needToTransformText || needToSecureText) {
119             RefPtr<StringImpl> textToTransform = originalString();
120             if (textToTransform)
121                 setText(textToTransform.get(), true);
122         }
123         // setText also calls cacheWidths(), so there is no need to call it again in that case.
124         else
125             cacheWidths();
126     }
127 }
128
129 void RenderText::destroy()
130 {
131     if (!documentBeingDestroyed()) {
132         if (firstTextBox()) {
133             if (isBR()) {
134                 RootInlineBox* next = firstTextBox()->root()->nextRootBox();
135                 if (next)
136                     next->markDirty();
137             }
138             for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
139                 box->remove();
140         }
141         else if (parent())
142             parent()->dirtyLinesFromChangedChild(this);
143     }
144     deleteTextBoxes();
145     RenderObject::destroy();
146 }
147
148 void RenderText::extractTextBox(InlineTextBox* box)
149 {
150     m_lastTextBox = box->prevTextBox();
151     if (box == m_firstTextBox)
152         m_firstTextBox = 0;
153     if (box->prevTextBox())
154         box->prevTextBox()->setNextLineBox(0);
155     box->setPreviousLineBox(0);
156     for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox())
157         curr->setExtracted();
158 }
159
160 void RenderText::attachTextBox(InlineTextBox* box)
161 {
162     if (m_lastTextBox) {
163         m_lastTextBox->setNextLineBox(box);
164         box->setPreviousLineBox(m_lastTextBox);
165     }
166     else
167         m_firstTextBox = box;
168     InlineTextBox* last = box;
169     for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {
170         curr->setExtracted(false);
171         last = curr;
172     }
173     m_lastTextBox = last;
174 }
175
176 void RenderText::removeTextBox(InlineTextBox* box)
177 {
178     if (box == m_firstTextBox)
179         m_firstTextBox = box->nextTextBox();
180     if (box == m_lastTextBox)
181         m_lastTextBox = box->prevTextBox();
182     if (box->nextTextBox())
183         box->nextTextBox()->setPreviousLineBox(box->prevTextBox());
184     if (box->prevTextBox())
185         box->prevTextBox()->setNextLineBox(box->nextTextBox());
186 }
187
188 void RenderText::deleteTextBoxes()
189 {
190     if (firstTextBox()) {
191         RenderArena* arena = renderArena();
192         InlineTextBox *curr = firstTextBox(), *next = 0;
193         while (curr) {
194             next = curr->nextTextBox();
195             curr->destroy(arena);
196             curr = next;
197         }
198         m_firstTextBox = m_lastTextBox = 0;
199     }
200 }
201
202 bool RenderText::isTextFragment() const
203 {
204     return false;
205 }
206
207 PassRefPtr<StringImpl> RenderText::originalString() const
208 {
209     return element() ? element()->string() : 0;
210 }
211
212 void RenderText::absoluteRects(DeprecatedValueList<IntRect>& rects, int _tx, int _ty)
213 {
214     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
215         rects.append(IntRect(_tx + box->xPos(), 
216                            _ty + box->yPos(), 
217                            box->width(), 
218                            box->height()));
219 }
220
221 DeprecatedValueList<IntRect> RenderText::lineBoxRects()
222 {
223     DeprecatedValueList<IntRect> rects;
224     int x = 0, y = 0;
225     absolutePositionForContent(x, y);
226     absoluteRects(rects, x, y);
227     return rects;
228 }
229
230 InlineTextBox* RenderText::findNextInlineTextBox(int offset, int &pos) const
231 {
232     // The text runs point to parts of the rendertext's str string
233     // (they don't include '\n')
234     // Find the text run that includes the character at @p offset
235     // and return pos, which is the position of the char in the run.
236
237     if (!m_firstTextBox)
238         return 0;
239     
240     InlineTextBox* s = m_firstTextBox;
241     int off = s->m_len;
242     while (offset > off && s->nextTextBox())
243     {
244         s = s->nextTextBox();
245         off = s->m_start + s->m_len;
246     }
247     // we are now in the correct text run
248     pos = (offset > off ? s->m_len : s->m_len - (off - offset) );
249     return s;
250 }
251
252 VisiblePosition RenderText::positionForCoordinates(int x, int y)
253 {
254     if (!firstTextBox() || stringLength() == 0)
255         return VisiblePosition(element(), 0, DOWNSTREAM);
256
257     int absx, absy;
258     RenderBlock* cb = containingBlock();
259     cb->absolutePositionForContent(absx, absy);
260     if (cb->hasOverflowClip())
261         cb->layer()->subtractScrollOffset(absx, absy);
262
263     // Get the offset for the position, since this will take rtl text into account.
264     int offset;
265     
266     // FIXME: We should be able to roll these special cases into the general cases in the loop below.
267     if (firstTextBox() && y < absy + firstTextBox()->root()->bottomOverflow() && x < absx + firstTextBox()->m_x) {
268         // at the y coordinate of the first line or above
269         // and the x coordinate is to the left of the first text box left edge
270         offset = firstTextBox()->offsetForPosition(x - absx);
271         return VisiblePosition(element(), offset + firstTextBox()->m_start, DOWNSTREAM);
272     }
273     if (lastTextBox() && y >= absy + lastTextBox()->root()->topOverflow() && x >= absx + lastTextBox()->m_x + lastTextBox()->m_width) {
274         // at the y coordinate of the last line or below
275         // and the x coordinate is to the right of the last text box right edge
276         offset = lastTextBox()->offsetForPosition(x - absx);
277         return VisiblePosition(element(), offset + lastTextBox()->m_start, DOWNSTREAM);
278     }
279
280     InlineTextBox* lastBoxAbove = 0;
281     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
282         if (y >= absy + box->root()->topOverflow()) {
283             if (y < absy + box->root()->bottomOverflow()) {
284                 offset = box->offsetForPosition(x - absx);
285
286                 if (x == absx + box->m_x)
287                     // the x coordinate is equal to the left edge of this box
288                     // the affinity must be downstream so the position doesn't jump back to the previous line
289                     return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM);
290
291                 if (x < absx + box->m_x + box->m_width)
292                     // and the x coordinate is to the left of the right edge of this box
293                     // check to see if position goes in this box
294                     return VisiblePosition(element(), offset + box->m_start, offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
295
296                 if (!box->prevOnLine() && x < absx + box->m_x)
297                     // box is first on line
298                     // and the x coordinate is to the left of the first text box left edge
299                     return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM);
300
301                 if (!box->nextOnLine())
302                     // box is last on line
303                     // and the x coordinate is to the right of the last text box right edge
304                     // generate VisiblePosition, use UPSTREAM affinity if possible
305                     return VisiblePosition(element(), offset + box->m_start, VP_UPSTREAM_IF_POSSIBLE);
306             }
307             lastBoxAbove = box;
308         }
309     }
310     
311     return VisiblePosition(element(), lastBoxAbove ? lastBoxAbove->m_start + lastBoxAbove->m_len : 0, DOWNSTREAM);
312 }
313
314 #if __GNUC__
315 static RenderObject *firstRendererOnNextLine(InlineBox *box) __attribute__ ((unused));
316 #endif
317 static RenderObject *firstRendererOnNextLine(InlineBox *box)
318 {
319     if (!box)
320         return 0;
321
322     RootInlineBox *root = box->root();
323     if (!root)
324         return 0;
325         
326     if (root->endsWithBreak())
327         return 0;
328     
329     RootInlineBox *nextRoot = root->nextRootBox();
330     if (!nextRoot)
331         return 0;
332     
333     InlineBox *firstChild = nextRoot->firstChild();
334     if (!firstChild)
335         return 0;
336
337     return firstChild->object();
338 }
339
340 static RenderObject *lastRendererOnPrevLine(InlineBox *box)
341 {
342     if (!box)
343         return 0;
344     
345     RootInlineBox *root = box->root();
346     if (!root)
347         return 0;
348     
349     if (root->endsWithBreak())
350         return 0;
351     
352     RootInlineBox *prevRoot = root->prevRootBox();
353     if (!prevRoot)
354         return 0;
355     
356     InlineBox *lastChild = prevRoot->lastChild();
357     if (!lastChild)
358         return 0;
359     
360     return lastChild->object();
361 }
362
363 static inline bool atLineWrap(InlineTextBox* box, int offset)
364 {
365     return box->nextTextBox() && !box->nextOnLine() && offset == box->m_start + box->m_len;
366 }
367
368 IntRect RenderText::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
369 {
370     if (!firstTextBox() || stringLength() == 0)
371         return IntRect();
372
373     // Find the text box for the given offset
374     InlineTextBox *box = 0;
375     for (box = firstTextBox(); box; box = box->nextTextBox()) {
376         if (box->containsCaretOffset(offset)) {
377             // Check if downstream affinity would make us move to the next line.
378             if (atLineWrap(box, offset) && affinity == DOWNSTREAM) {
379                 // Use the next text box
380                 box = box->nextTextBox();
381                 offset = box->m_start;
382             } else {
383                 InlineTextBox *prevBox = box->prevTextBox();
384                 if (offset == box->m_start && affinity == UPSTREAM && prevBox && !box->prevOnLine()) {
385                     if (prevBox) {
386                         box = prevBox;
387                         offset = box->m_start + box->m_len;
388                     } else {
389                         RenderObject *object = lastRendererOnPrevLine(box);
390                         if (object)
391                             return object->caretRect(0, affinity);
392                     }
393                 }
394             }
395             break;
396         }
397     }
398     
399     if (!box) {
400         return IntRect();
401     }
402
403     int height = box->root()->bottomOverflow() - box->root()->topOverflow();
404     int top = box->root()->topOverflow();
405
406     int left = box->positionForOffset(offset);
407
408     int rootLeft = box->root()->xPos();
409     // FIXME: should we use the width of the root inline box or the
410     // width of the containing block for this?
411     if (extraWidthToEndOfLine)
412         *extraWidthToEndOfLine = (box->root()->width() + rootLeft) - (left + 1);
413
414     int absx, absy;
415     absolutePositionForContent(absx, absy);
416     left += absx;
417     top += absy;
418
419     RenderBlock *cb = containingBlock();
420     if (style()->autoWrap()) {
421         int availableWidth = cb->lineWidth(top);
422         if (!box->m_reversed)
423             left = min(left, absx + rootLeft + availableWidth - 1);
424         else
425             left = max(left, absx + rootLeft);
426     }
427      
428     return IntRect(left, top, 1, height);
429 }
430
431 void RenderText::posOfChar(int chr, int &x, int &y)
432 {
433     absolutePositionForContent(x, y);
434
435     int pos;
436     if (InlineTextBox* s = findNextInlineTextBox(chr, pos)) {
437         // s is the line containing the character
438         x += s->m_x; // this is the x of the beginning of the line, but it's good enough for now
439         y += s->m_y;
440     }
441 }
442
443 bool RenderText::allAscii() const
444 {
445     if (m_allAsciiChecked)
446         return m_allAscii;
447     m_allAsciiChecked = true;
448     
449     unsigned i;
450     for (i = 0; i < str->length(); i++)
451         if ((*str)[i] > 0x7f) {
452             m_allAscii = false;
453             return m_allAscii;
454         }
455     
456     m_allAscii = true;
457     
458     return m_allAscii;
459 }
460
461 bool RenderText::shouldUseMonospaceCache(const Font *f) const
462 {
463     return (f && f->isFixedPitch() && allAscii() && !style()->font().isSmallCaps());
464 }
465
466 // We cache the width of the ' ' character for <pre> text.  We could go further
467 // and cache a widths array for all styles, at the expense of increasing the size of the
468 // RenderText.
469 void RenderText::cacheWidths()
470 {
471     const Font* f = font(false);
472     if (shouldUseMonospaceCache(f)) {
473         const UChar c = ' ';
474         m_monospaceCharacterWidth = f->width(TextRun(&c, 1));
475     } else {
476         m_monospaceCharacterWidth = 0;
477     }
478 }
479
480 ALWAYS_INLINE int RenderText::widthFromCache(const Font* f, int start, int len, int tabWidth, int xpos) const
481 {
482     if (m_monospaceCharacterWidth != 0) {
483         int i, w = 0;
484         for (i = start; i < start+len; i++) {
485             UChar c = (*str)[i];
486             UCharDirection dir = u_charDirection(c);
487             if (dir != U_DIR_NON_SPACING_MARK && dir != U_BOUNDARY_NEUTRAL) {
488                 if (c == '\t' && tabWidth != 0)
489                     w += tabWidth - ((xpos + w) % tabWidth);
490                 else
491                     w += m_monospaceCharacterWidth;
492                 if (DeprecatedChar(c).isSpace() && i > start && !DeprecatedChar((*str)[i - 1]).isSpace())
493                     w += f->wordSpacing();        
494             }
495         }
496
497         return w;
498     }
499     
500     return f->width(TextRun(string(), start, len, 0), TextStyle(tabWidth, xpos));
501 }
502
503 void RenderText::trimmedMinMaxWidth(int leadWidth,
504                                     int& beginMinW, bool& beginWS, 
505                                     int& endMinW, bool& endWS,
506                                     bool& hasBreakableChar, bool& hasBreak,
507                                     int& beginMaxW, int& endMaxW,
508                                     int& minW, int& maxW, bool& stripFrontSpaces)
509 {
510     bool collapseWhiteSpace = style()->collapseWhiteSpace();
511     if (!collapseWhiteSpace)
512         stripFrontSpaces = false;
513     
514     int len = str->length();
515     if (len == 0 || (stripFrontSpaces && str->containsOnlyWhitespace())) {
516         maxW = 0;
517         hasBreak = false;
518         return;
519     }
520     
521     // if the text has a variable width tab, we need to call 
522     if (m_hasTab)
523         calcMinMaxWidth(leadWidth);
524     
525     minW = m_minWidth;
526     maxW = m_maxWidth;
527     beginWS = !stripFrontSpaces && m_hasBeginWS;
528     endWS = m_hasEndWS;
529     
530     beginMinW = m_beginMinWidth;
531     endMinW = m_endMinWidth;
532     
533     hasBreakableChar = m_hasBreakableChar;
534     hasBreak = m_hasBreak;
535
536     if (stripFrontSpaces && ((*str)[0] == ' ' || ((*str)[0] == '\n' && !style()->preserveNewline()) || (*str)[0] == '\t')) {
537         const Font *f = font(false); // FIXME: Why is it ok to ignore first-line here?
538         const UChar space = ' ';
539         int spaceWidth = f->width(TextRun(&space, 1));
540         maxW -= spaceWidth + f->wordSpacing();
541     }
542     
543     stripFrontSpaces = collapseWhiteSpace && m_hasEndWS;
544     
545     if (!style()->autoWrap() || minW > maxW)
546         minW = maxW;
547
548     // Compute our max widths by scanning the string for newlines.
549     if (hasBreak) {
550         const Font *f = font(false);
551         bool firstLine = true;
552         beginMaxW = endMaxW = maxW;
553         for (int i = 0; i < len; i++)
554         {
555             int linelen = 0;
556             while (i+linelen < len && (*str)[i+linelen] != '\n')
557                 linelen++;
558                 
559             if (linelen)
560             {
561                 endMaxW = widthFromCache(f, i, linelen, tabWidth(), leadWidth + endMaxW);
562                 if (firstLine) {
563                     firstLine = false;
564                     leadWidth = 0;
565                     beginMaxW = endMaxW;
566                 }
567                 i += linelen;
568             }
569             else if (firstLine) {
570                 beginMaxW = 0;
571                 firstLine = false;
572                 leadWidth = 0;
573             }
574     
575             if (i == len-1)
576                 // A <pre> run that ends with a newline, as in, e.g.,
577                 // <pre>Some text\n\n<span>More text</pre>
578                 endMaxW = 0;
579         }
580     }
581 }
582
583 void RenderText::calcMinMaxWidth()
584 {
585     // Use 0 for the leadWidth.   If the text contains a variable width tab, the real width
586     // will get measured when trimmedMinMaxWidth calls again with the real leadWidth.
587     ASSERT( !minMaxKnown() );
588     calcMinMaxWidth(0);
589 }
590
591 void RenderText::calcMinMaxWidth(int leadWidth)
592 {
593     // ### calc Min and Max width...
594     m_minWidth = m_beginMinWidth = m_endMinWidth = 0;
595     m_maxWidth = 0;
596
597     if (isBR())
598         return;
599         
600     int currMinWidth = 0;
601     int currMaxWidth = 0;
602     m_hasBreakableChar = m_hasBreak = m_hasTab = m_hasBeginWS = m_hasEndWS = false;
603     
604     // FIXME: not 100% correct for first-line
605     const Font* f = font(false);
606     int wordSpacing = style()->wordSpacing();
607     int len = str->length();
608     const UChar* txt = str->characters();
609     bool needsWordSpacing = false;
610     bool ignoringSpaces = false;
611     bool isSpace = false;
612     bool firstWord = true;
613     bool firstLine = true;
614     int nextBreakable = -1;
615     for (int i = 0; i < len; i++) {
616         UChar c = txt[i];
617         
618         bool previousCharacterIsSpace = isSpace;
619         
620         bool isNewline = false;
621         if (c == '\n') {
622             if (style()->preserveNewline()) {
623                 m_hasBreak = true;
624                 isNewline = true;
625                 isSpace = false;
626             } else
627                 isSpace = true;
628         } else if (c == '\t') {
629             if (!style()->collapseWhiteSpace()) {
630                 m_hasTab = true;
631                 isSpace = false;
632             } else
633                 isSpace = true;
634         } else {
635             isSpace = c == ' ';
636         }
637         
638         if ((isSpace || isNewline) && i == 0)
639             m_hasBeginWS = true;
640         if ((isSpace || isNewline) && i == len-1)
641             m_hasEndWS = true;
642             
643         if (!ignoringSpaces && style()->collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
644             ignoringSpaces = true;
645         
646         if (ignoringSpaces && !isSpace)
647             ignoringSpaces = false;
648         
649         // Ignore spaces and soft hyphens
650         if (ignoringSpaces || c == SOFT_HYPHEN) {
651             continue;
652         }
653         
654         bool hasBreak = isBreakable(txt, i, len, nextBreakable);
655         int j = i;
656         while (c != '\n' && c != ' ' && c != '\t' && c != SOFT_HYPHEN) {
657             j++;
658             if (j == len)
659                 break;
660             c = txt[j];
661             if (isBreakable(txt, j, len, nextBreakable))
662                 break;
663         }
664             
665         int wordlen = j - i;
666         if (wordlen) {
667             int w = widthFromCache(f, i, wordlen, tabWidth(), leadWidth + currMaxWidth);
668             currMinWidth += w;
669             currMaxWidth += w;
670             
671             bool isSpace = (j < len) && c == ' ';
672             bool isCollapsibleWhiteSpace = (j < len) && style()->isCollapsibleWhiteSpace(c);
673             if (j < len && style()->autoWrap())
674                 m_hasBreakableChar = true;
675             
676             // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
677             // last word in the run.
678             if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
679                 currMaxWidth += wordSpacing;
680
681             if (firstWord) {
682                 firstWord = false;
683                 // If the first character in the run is breakable, then we consider ourselves to have a beginning
684                 // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
685                 // being appended to a previous text run when considering the total minimum width of the containing block.
686                 if (hasBreak)
687                     m_hasBreakableChar = true;
688                 m_beginMinWidth = hasBreak ? 0 : w;
689             }
690             m_endMinWidth = w;
691             
692             if (currMinWidth > m_minWidth) m_minWidth = currMinWidth;
693             currMinWidth = 0;
694             
695             i += wordlen-1;
696         }
697         else {
698             // Nowrap can never be broken, so don't bother setting the
699             // breakable character boolean. Pre can only be broken if we encounter a newline.     
700             if (style()->autoWrap() || isNewline)
701                 m_hasBreakableChar = true;
702
703             if (currMinWidth > m_minWidth) m_minWidth = currMinWidth;
704             currMinWidth = 0;
705             
706             if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
707                 if (firstLine) {
708                     firstLine = false;
709                     leadWidth = 0;
710                     m_beginMinWidth = currMaxWidth;
711                 }
712                 
713                 if (currMaxWidth > m_maxWidth) m_maxWidth = currMaxWidth;
714                 currMaxWidth = 0;
715             }
716             else
717             {
718                 currMaxWidth += f->width(TextRun(txt + i, 1), TextStyle(tabWidth(), leadWidth + currMaxWidth));
719                 needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len-1;
720             }
721         }
722     }
723
724     if (needsWordSpacing && len > 1) 
725         currMaxWidth += wordSpacing;
726     
727     m_minWidth = max(currMinWidth, m_minWidth);
728     m_maxWidth = max(currMaxWidth, m_maxWidth);
729         
730     if (!style()->autoWrap())
731         m_minWidth = m_maxWidth;
732
733     if (style()->whiteSpace() == PRE) {
734         // FIXME: pre-wrap and pre-line need to be dealt with possibly?  This code won't be right
735         // for them though.
736         if (firstLine)
737             m_beginMinWidth = m_maxWidth;
738         m_endMinWidth = currMaxWidth;
739     }
740     
741     setMinMaxKnown();
742     //kdDebug( 6040 ) << "Text::calcMinMaxWidth(): min = " << m_minWidth << " max = " << m_maxWidth << endl;
743 }
744
745 bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
746 {
747     unsigned currPos;
748     for (currPos = from; 
749          currPos < from+len && ((*str)[currPos] == '\n' || (*str)[currPos] == ' ' || (*str)[currPos] == '\t'); 
750          currPos++);
751     return currPos >= (from+len);
752 }
753
754 int RenderText::minXPos() const
755 {
756     if (!m_firstTextBox) return 0;
757     int retval=6666666;
758     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
759         retval = min(retval, (int)box->m_x);
760     return retval;
761 }
762
763 int RenderText::xPos() const
764 {
765     return m_firstTextBox ? m_firstTextBox->m_x : 0;
766 }
767
768 int RenderText::yPos() const
769 {
770     return m_firstTextBox ? m_firstTextBox->m_y : 0;
771 }
772
773 const Font& RenderText::font()
774 {
775     return style()->font();
776 }
777
778 void RenderText::setSelectionState(SelectionState s)
779 {
780     InlineTextBox* box;
781     
782     m_selectionState = s;
783     if (s == SelectionStart || s == SelectionEnd || s == SelectionBoth) {
784         int startPos, endPos;
785         selectionStartEnd(startPos, endPos);
786         if(selectionState() == SelectionStart) {
787             endPos = str->length();
788             
789             // to handle selection from end of text to end of line
790             if (startPos != 0 && startPos == endPos) {
791                 startPos = endPos - 1;
792             }
793         } else if(selectionState() == SelectionEnd)
794             startPos = 0;
795         
796         for (box = firstTextBox(); box; box = box->nextTextBox()) {
797             if (box->isSelected(startPos, endPos)) {
798                 RootInlineBox* line = box->root();
799                 if (line)
800                     line->setHasSelectedChildren(true);
801             }
802         }
803     }
804     else {
805         for (box = firstTextBox(); box; box = box->nextTextBox()) {
806             RootInlineBox* line = box->root();
807             if (line)
808                 line->setHasSelectedChildren(s == SelectionInside);
809         }
810     }
811     
812     containingBlock()->setSelectionState(s);
813 }
814
815 void RenderText::setTextWithOffset(StringImpl *text, unsigned offset, unsigned len, bool force)
816 {
817     unsigned oldLen = str ? str->length() : 0;
818     unsigned newLen = text ? text->length() : 0;
819     int delta = newLen - oldLen;
820     unsigned end = len ? offset+len-1 : offset;
821
822     RootInlineBox* firstRootBox = 0;
823     RootInlineBox* lastRootBox = 0;
824     
825     bool dirtiedLines = false;
826     
827     // Dirty all text boxes that include characters in between offset and offset+len.
828     for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
829         // Text run is entirely before the affected range.
830         if (curr->end() < offset)
831             continue;
832         
833         // Text run is entirely after the affected range.
834         if (curr->start() > end) {
835             curr->offsetRun(delta);
836             RootInlineBox* root = curr->root();
837             if (!firstRootBox) {
838                 firstRootBox = root;
839                 if (!dirtiedLines) { // The affected area was in between two runs. Go ahead and mark the root box of the run after the affected area as dirty.
840                     firstRootBox->markDirty();
841                     dirtiedLines = true;
842                 }
843             }
844             lastRootBox = root;
845         }
846         else if (curr->end() >= offset && curr->end() <= end) {
847             curr->dirtyLineBoxes(); // Text run overlaps with the left end of the affected range.
848             dirtiedLines = true;
849         }
850         else if (curr->start() <= offset && curr->end() >= end) {
851             curr->dirtyLineBoxes(); // Text run subsumes the affected range.
852             dirtiedLines = true;
853         }
854         else if (curr->start() <= end && curr->end() >= end) {
855             curr->dirtyLineBoxes(); // Text run overlaps with right end of the affected range.
856             dirtiedLines = true;
857         }
858     }
859     
860     // Now we have to walk all of the clean lines and adjust their cached line break information
861     // to reflect our updated offsets.
862     if (lastRootBox)
863         lastRootBox = lastRootBox->nextRootBox();
864     if (firstRootBox) {
865         RootInlineBox* prev = firstRootBox->prevRootBox();
866         if (prev)
867             firstRootBox = prev;
868     }
869     for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
870         if (curr->lineBreakObj() == this && curr->lineBreakPos() > end)
871             curr->setLineBreakPos(curr->lineBreakPos()+delta);
872     }
873     
874     m_linesDirty = dirtiedLines;
875     setText(text, force);
876 }
877
878 #define BULLET_CHAR 0x2022
879 #define SQUARE_CHAR 0x25AA
880 #define CIRCLE_CHAR 0x25E6
881
882 void RenderText::setText(StringImpl *text, bool force)
883 {
884     if (!text)
885         return;
886     if (!force && str == text)
887         return;
888
889     m_allAsciiChecked = false;
890
891     str = text;
892     if (str) {
893         str = str->replace('\\', backslashAsCurrencySymbol());
894         if (style()) {
895             switch (style()->textTransform()) {
896                 case CAPITALIZE:
897                 {
898                     // find previous text renderer if one exists
899                     RenderObject* o;
900                     UChar previous = ' ';
901                     for (o = previousInPreOrder(); o && (o->isInlineFlow() || o->isText() && static_cast<RenderText*>(o)->string()->length() == 0); o = o->previousInPreOrder())
902                         ;
903                     if (o && o->isText()) {
904                         StringImpl* prevStr = static_cast<RenderText*>(o)->string();
905                         previous = (*prevStr)[prevStr->length() - 1];
906                     }
907                     str = str->capitalize(previous);
908                 }
909                     break;
910                 case UPPERCASE:  str = str->upper();       break;
911                 case LOWERCASE:  str = str->lower();       break;
912                 case NONE:
913                 default:;
914             }
915             
916             switch(style()->textSecurity()) {
917                 case TSDISC:
918                     str = str->secure(BULLET_CHAR);
919                     break;
920                 case TSCIRCLE:
921                     str = str->secure(CIRCLE_CHAR);
922                     break;
923                 case TSSQUARE: 
924                     str = str->secure(SQUARE_CHAR);
925                     break;
926                 case TSNONE:
927                     break;
928             }
929         }
930     }
931
932     cacheWidths();
933
934     // ### what should happen if we change the text of a
935     // RenderBR object ?
936     ASSERT(!isBR() || (str->length() == 1 && (*str)[0] == '\n'));
937     ASSERT(!str->length() || str->characters());
938
939     setNeedsLayoutAndMinMaxRecalc();
940 }
941
942 int RenderText::height() const
943 {
944     int retval = 0;
945     if (firstTextBox())
946         retval = lastTextBox()->m_y + lastTextBox()->height() - firstTextBox()->m_y;
947     return retval;
948 }
949
950 short RenderText::lineHeight(bool firstLine, bool) const
951 {
952     // Always use the interior line height of the parent (e.g., if our parent is an inline block).
953     return parent()->lineHeight(firstLine, true);
954 }
955
956 void RenderText::dirtyLineBoxes(bool fullLayout, bool)
957 {
958     if (fullLayout)
959         deleteTextBoxes();
960     else if (!m_linesDirty) {
961         for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
962             box->dirtyLineBoxes();
963     }
964     m_linesDirty = false;
965 }
966
967 InlineBox* RenderText::createInlineBox(bool, bool isRootLineBox, bool)
968 {
969     ASSERT(!isRootLineBox);
970     InlineTextBox* textBox = new (renderArena()) InlineTextBox(this);
971     if (!m_firstTextBox)
972         m_firstTextBox = m_lastTextBox = textBox;
973     else {
974         m_lastTextBox->setNextLineBox(textBox);
975         textBox->setPreviousLineBox(m_lastTextBox);
976         m_lastTextBox = textBox;
977     }
978     return textBox;
979 }
980
981 void RenderText::position(InlineBox* box)
982 {
983     InlineTextBox *s = static_cast<InlineTextBox*>(box);
984     
985     // ### should not be needed!!!
986     if (s->m_len == 0) {
987         // We want the box to be destroyed.
988         s->remove();
989         s->destroy(renderArena());
990         m_firstTextBox = m_lastTextBox = 0;
991         return;
992     }
993     
994     m_containsReversedText |= s->m_reversed;
995 }
996
997 unsigned int RenderText::width(unsigned int from, unsigned int len, int xpos, bool firstLine) const
998 {
999     if (from >= str->length())
1000         return 0;
1001     if (from + len > str->length())
1002         len = str->length() - from;
1003
1004     const Font *f = font(firstLine);
1005     return width(from, len, f, xpos);
1006 }
1007
1008 unsigned int RenderText::width(unsigned int from, unsigned int len, const Font *f, int xpos) const
1009 {
1010     if (!str->characters() || from > str->length())
1011         return 0;
1012     if (from + len > str->length())
1013         len = str->length() - from;
1014
1015     int w;
1016     if (!style()->preserveNewline() && f == &style()->font() && from == 0 && len == str->length())
1017         w = m_maxWidth;
1018     else if (f == &style()->font())
1019         w = widthFromCache(f, from, len, tabWidth(), xpos);
1020     else
1021         w = f->width(TextRun(string(), from, len, 0), TextStyle(tabWidth(), xpos));
1022         
1023     return w;
1024 }
1025
1026 int RenderText::width() const
1027 {
1028     int minx = 100000000;
1029     int maxx = 0;
1030     // slooow
1031     for (InlineTextBox* s = firstTextBox(); s; s = s->nextTextBox()) {
1032         if(s->m_x < minx)
1033             minx = s->m_x;
1034         if(s->m_x + s->m_width > maxx)
1035             maxx = s->m_x + s->m_width;
1036     }
1037
1038     return max(0, maxx-minx);
1039 }
1040
1041 IntRect RenderText::getAbsoluteRepaintRect()
1042 {
1043     RenderObject *cb = containingBlock();
1044     return cb->getAbsoluteRepaintRect();
1045 }
1046
1047 IntRect RenderText::selectionRect()
1048 {
1049     IntRect rect;
1050     if (selectionState() == SelectionNone)
1051         return rect;
1052     RenderBlock* cb =  containingBlock();
1053     if (!cb)
1054         return rect;
1055     
1056     // Now calculate startPos and endPos for painting selection.
1057     // We include a selection while endPos > 0
1058     int startPos, endPos;
1059     if (selectionState() == SelectionInside) {
1060         // We are fully selected.
1061         startPos = 0;
1062         endPos = str->length();
1063     } else {
1064         selectionStartEnd(startPos, endPos);
1065         if (selectionState() == SelectionStart)
1066             endPos = str->length();
1067         else if (selectionState() == SelectionEnd)
1068             startPos = 0;
1069     }
1070     
1071     if (startPos == endPos)
1072         return rect;
1073
1074     int absx, absy;
1075     cb->absolutePositionForContent(absx, absy);
1076     RenderLayer* layer = cb->layer();
1077     if (layer)
1078        layer->subtractScrollOffset(absx, absy); 
1079     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1080         rect.unite(box->selectionRect(absx, absy, startPos, endPos));
1081
1082     return rect;
1083 }
1084
1085 short RenderText::verticalPositionHint( bool firstLine ) const
1086 {
1087     return parent()->verticalPositionHint( firstLine );
1088 }
1089
1090 const Font *RenderText::font(bool firstLine) const
1091 {
1092     return &style(firstLine)->font();
1093 }
1094
1095 int RenderText::caretMinOffset() const
1096 {
1097     InlineTextBox *box = firstTextBox();
1098     if (!box)
1099         return 0;
1100     int minOffset = box->m_start;
1101     for (box = box->nextTextBox(); box; box = box->nextTextBox())
1102         minOffset = min(minOffset, box->m_start);
1103     return minOffset;
1104 }
1105
1106 int RenderText::caretMaxOffset() const
1107 {
1108     InlineTextBox* box = lastTextBox();
1109     if (!box) 
1110         return str->length();
1111     int maxOffset = box->m_start + box->m_len;
1112     for (box = box->prevTextBox(); box; box = box->prevTextBox())
1113         maxOffset = max(maxOffset,box->m_start + box->m_len);
1114     return maxOffset;
1115 }
1116
1117 unsigned RenderText::caretMaxRenderedOffset() const
1118 {
1119     int l = 0;
1120     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1121         l += box->m_len;
1122     return l;
1123 }
1124
1125 InlineBox* RenderText::inlineBox(int offset, EAffinity affinity)
1126 {
1127     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1128         if (box->containsCaretOffset(offset)) {
1129             if (atLineWrap(box, offset) && affinity == DOWNSTREAM)
1130                 return box->nextTextBox();
1131             return box;
1132         }
1133         if (offset < box->m_start)
1134             // The offset we're looking for is before this node
1135             // this means the offset must be in content that is
1136             // not rendered.
1137             return box->prevTextBox() ? box->prevTextBox() : firstTextBox();
1138     }
1139     
1140     return 0;
1141 }
1142
1143 }