1/*
2 * (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2000 Dirk Mueller (mueller@kde.org)
4 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
5 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
6 * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 "RenderText.h"
27
28#include "AXObjectCache.h"
29#include "EllipsisBox.h"
30#include "FloatQuad.h"
31#include "FontTranscoder.h"
32#include "FrameView.h"
33#include "InlineTextBox.h"
34#include "Range.h"
35#include "RenderArena.h"
36#include "RenderBlock.h"
37#include "RenderCombineText.h"
38#include "RenderLayer.h"
39#include "RenderView.h"
40#include "Settings.h"
41#include "Text.h"
42#include "TextBreakIterator.h"
43#include "TextResourceDecoder.h"
44#include "TextRun.h"
45#include "VisiblePosition.h"
46#include "break_lines.h"
47#include <wtf/AlwaysInline.h>
48#include <wtf/text/StringBuffer.h>
49#include <wtf/unicode/CharacterNames.h>
50
51using namespace std;
52using namespace WTF;
53using namespace Unicode;
54
55namespace WebCore {
56
57class SecureTextTimer;
58typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap;
59static SecureTextTimerMap* gSecureTextTimers = 0;
60
61class SecureTextTimer : public TimerBase {
62public:
63    SecureTextTimer(RenderText* renderText)
64        : m_renderText(renderText)
65        , m_lastTypedCharacterOffset(-1)
66    {
67    }
68
69    void restartWithNewText(unsigned lastTypedCharacterOffset)
70    {
71        m_lastTypedCharacterOffset = lastTypedCharacterOffset;
72        startOneShot(m_renderText->document()->settings()->passwordEchoDurationInSeconds());
73    }
74    void invalidate() { m_lastTypedCharacterOffset = -1; }
75    unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; }
76
77private:
78    virtual void fired()
79    {
80        ASSERT(gSecureTextTimers->contains(m_renderText));
81        m_renderText->setText(m_renderText->text(), true /* forcing setting text as it may be masked later */);
82    }
83
84    RenderText* m_renderText;
85    int m_lastTypedCharacterOffset;
86};
87
88static void makeCapitalized(String* string, UChar previous)
89{
90    if (string->isNull())
91        return;
92
93    unsigned length = string->length();
94    const UChar* characters = string->characters();
95
96    if (length >= numeric_limits<unsigned>::max())
97        CRASH();
98
99    StringBuffer stringWithPrevious(length + 1);
100    stringWithPrevious[0] = previous == noBreakSpace ? ' ' : previous;
101    for (unsigned i = 1; i < length + 1; i++) {
102        // Replace &nbsp with a real space since ICU no longer treats &nbsp as a word separator.
103        if (characters[i - 1] == noBreakSpace)
104            stringWithPrevious[i] = ' ';
105        else
106            stringWithPrevious[i] = characters[i - 1];
107    }
108
109    TextBreakIterator* boundary = wordBreakIterator(stringWithPrevious.characters(), length + 1);
110    if (!boundary)
111        return;
112
113    StringBuffer data(length);
114
115    int32_t endOfWord;
116    int32_t startOfWord = textBreakFirst(boundary);
117    for (endOfWord = textBreakNext(boundary); endOfWord != TextBreakDone; startOfWord = endOfWord, endOfWord = textBreakNext(boundary)) {
118        if (startOfWord != 0) // Ignore first char of previous string
119            data[startOfWord - 1] = characters[startOfWord - 1] == noBreakSpace ? noBreakSpace : toTitleCase(stringWithPrevious[startOfWord]);
120        for (int i = startOfWord + 1; i < endOfWord; i++)
121            data[i - 1] = characters[i - 1];
122    }
123
124    *string = String::adopt(data);
125}
126
127RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
128     : RenderObject(node)
129     , m_minWidth(-1)
130     , m_text(str)
131     , m_firstTextBox(0)
132     , m_lastTextBox(0)
133     , m_maxWidth(-1)
134     , m_beginMinWidth(0)
135     , m_endMinWidth(0)
136     , m_hasTab(false)
137     , m_linesDirty(false)
138     , m_containsReversedText(false)
139     , m_isAllASCII(m_text.containsOnlyASCII())
140     , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
141     , m_needsTranscoding(false)
142{
143    ASSERT(m_text);
144
145    setIsText();
146
147    // FIXME: It would be better to call this only if !m_text->containsOnlyWhitespace().
148    // But that might slow things down, and maybe should only be done if visuallyNonEmpty
149    // is still false. Not making any change for now, but should consider in the future.
150    view()->frameView()->setIsVisuallyNonEmpty();
151}
152
153#ifndef NDEBUG
154
155RenderText::~RenderText()
156{
157    ASSERT(!m_firstTextBox);
158    ASSERT(!m_lastTextBox);
159}
160
161#endif
162
163const char* RenderText::renderName() const
164{
165    return "RenderText";
166}
167
168bool RenderText::isTextFragment() const
169{
170    return false;
171}
172
173bool RenderText::isWordBreak() const
174{
175    return false;
176}
177
178void RenderText::updateNeedsTranscoding()
179{
180    const TextEncoding* encoding = document()->decoder() ? &document()->decoder()->encoding() : 0;
181    m_needsTranscoding = fontTranscoder().needsTranscoding(style()->font().fontDescription(), encoding);
182}
183
184void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
185{
186    // There is no need to ever schedule repaints from a style change of a text run, since
187    // we already did this for the parent of the text run.
188    // We do have to schedule layouts, though, since a style change can force us to
189    // need to relayout.
190    if (diff == StyleDifferenceLayout) {
191        setNeedsLayoutAndPrefWidthsRecalc();
192        m_knownToHaveNoOverflowAndNoFallbackFonts = false;
193    }
194
195    bool needsResetText = false;
196    if (!oldStyle) {
197        updateNeedsTranscoding();
198        needsResetText = m_needsTranscoding;
199    } else if (oldStyle->font().needsTranscoding() != style()->font().needsTranscoding() || (style()->font().needsTranscoding() && oldStyle->font().family().family() != style()->font().family().family())) {
200        updateNeedsTranscoding();
201        needsResetText = true;
202    }
203
204    ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
205    ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
206    if (needsResetText || oldTransform != style()->textTransform() || oldSecurity != style()->textSecurity()) {
207        if (RefPtr<StringImpl> textToTransform = originalText())
208            setText(textToTransform.release(), true);
209    }
210}
211
212void RenderText::removeAndDestroyTextBoxes()
213{
214    if (!documentBeingDestroyed()) {
215        if (firstTextBox()) {
216            if (isBR()) {
217                RootInlineBox* next = firstTextBox()->root()->nextRootBox();
218                if (next)
219                    next->markDirty();
220            }
221            for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
222                box->remove();
223        } else if (parent())
224            parent()->dirtyLinesFromChangedChild(this);
225    }
226    deleteTextBoxes();
227}
228
229void RenderText::destroy()
230{
231    if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->take(this) : 0)
232        delete secureTextTimer;
233
234    removeAndDestroyTextBoxes();
235    RenderObject::destroy();
236}
237
238void RenderText::extractTextBox(InlineTextBox* box)
239{
240    checkConsistency();
241
242    m_lastTextBox = box->prevTextBox();
243    if (box == m_firstTextBox)
244        m_firstTextBox = 0;
245    if (box->prevTextBox())
246        box->prevTextBox()->setNextTextBox(0);
247    box->setPreviousTextBox(0);
248    for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox())
249        curr->setExtracted();
250
251    checkConsistency();
252}
253
254void RenderText::attachTextBox(InlineTextBox* box)
255{
256    checkConsistency();
257
258    if (m_lastTextBox) {
259        m_lastTextBox->setNextTextBox(box);
260        box->setPreviousTextBox(m_lastTextBox);
261    } else
262        m_firstTextBox = box;
263    InlineTextBox* last = box;
264    for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {
265        curr->setExtracted(false);
266        last = curr;
267    }
268    m_lastTextBox = last;
269
270    checkConsistency();
271}
272
273void RenderText::removeTextBox(InlineTextBox* box)
274{
275    checkConsistency();
276
277    if (box == m_firstTextBox)
278        m_firstTextBox = box->nextTextBox();
279    if (box == m_lastTextBox)
280        m_lastTextBox = box->prevTextBox();
281    if (box->nextTextBox())
282        box->nextTextBox()->setPreviousTextBox(box->prevTextBox());
283    if (box->prevTextBox())
284        box->prevTextBox()->setNextTextBox(box->nextTextBox());
285
286    checkConsistency();
287}
288
289void RenderText::deleteTextBoxes()
290{
291    if (firstTextBox()) {
292        RenderArena* arena = renderArena();
293        InlineTextBox* next;
294        for (InlineTextBox* curr = firstTextBox(); curr; curr = next) {
295            next = curr->nextTextBox();
296            curr->destroy(arena);
297        }
298        m_firstTextBox = m_lastTextBox = 0;
299    }
300}
301
302PassRefPtr<StringImpl> RenderText::originalText() const
303{
304    Node* e = node();
305    return (e && e->isTextNode()) ? static_cast<Text*>(e)->dataImpl() : 0;
306}
307
308void RenderText::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
309{
310    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
311        rects.append(enclosingIntRect(FloatRect(tx + box->x(), ty + box->y(), box->width(), box->height())));
312}
313
314void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight)
315{
316    // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
317    // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
318    // function to take ints causes various internal mismatches. But selectionRect takes ints, and
319    // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
320    // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
321    ASSERT(end == UINT_MAX || end <= INT_MAX);
322    ASSERT(start <= INT_MAX);
323    start = min(start, static_cast<unsigned>(INT_MAX));
324    end = min(end, static_cast<unsigned>(INT_MAX));
325
326    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
327        // Note: box->end() returns the index of the last character, not the index past it
328        if (start <= box->start() && box->end() < end) {
329            IntRect r = IntRect(box->x(), box->y(), box->logicalWidth(), box->logicalHeight());
330            if (useSelectionHeight) {
331                IntRect selectionRect = box->selectionRect(0, 0, start, end);
332                r.setHeight(selectionRect.height());
333                r.setY(selectionRect.y());
334            }
335            FloatPoint origin = localToAbsolute(r.location());
336            r.setX(origin.x());
337            r.setY(origin.y());
338            rects.append(r);
339        } else {
340            unsigned realEnd = min(box->end() + 1, end);
341            IntRect r = box->selectionRect(0, 0, start, realEnd);
342            if (!r.isEmpty()) {
343                if (!useSelectionHeight) {
344                    // change the height and y position because selectionRect uses selection-specific values
345                    r.setHeight(box->logicalHeight());
346                    r.setY(box->y());
347                }
348                FloatPoint origin = localToAbsolute(r.location());
349                localToAbsolute(origin);
350                r.setX(origin.x());
351                r.setY(origin.y());
352                rects.append(r);
353            }
354        }
355    }
356}
357
358static IntRect ellipsisRectForBox(InlineTextBox* box, unsigned startPos, unsigned endPos)
359{
360    if (!box)
361        return IntRect();
362
363    unsigned short truncation = box->truncation();
364    if (truncation == cNoTruncation)
365        return IntRect();
366
367    IntRect rect;
368    if (EllipsisBox* ellipsis = box->root()->ellipsisBox()) {
369        int ellipsisStartPosition = max<int>(startPos - box->start(), 0);
370        int ellipsisEndPosition = min<int>(endPos - box->start(), box->len());
371
372        // The ellipsis should be considered to be selected if the end of
373        // the selection is past the beginning of the truncation and the
374        // beginning of the selection is before or at the beginning of the truncation.
375        if (ellipsisEndPosition >= truncation && ellipsisStartPosition <= truncation)
376            return ellipsis->selectionRect(0, 0);
377    }
378
379    return IntRect();
380}
381
382void RenderText::absoluteQuads(Vector<FloatQuad>& quads, ClippingOption option)
383{
384    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
385        IntRect boundaries = box->calculateBoundaries();
386
387        // Shorten the width of this text box if it ends in an ellipsis.
388        IntRect ellipsisRect = (option == ClipToEllipsis) ? ellipsisRectForBox(box, 0, textLength()) : IntRect();
389        if (!ellipsisRect.isEmpty()) {
390            if (style()->isHorizontalWritingMode())
391                boundaries.setWidth(ellipsisRect.maxX() - boundaries.x());
392            else
393                boundaries.setHeight(ellipsisRect.maxY() - boundaries.y());
394        }
395        quads.append(localToAbsoluteQuad(FloatRect(boundaries)));
396    }
397}
398
399void RenderText::absoluteQuads(Vector<FloatQuad>& quads)
400{
401    absoluteQuads(quads, NoClipping);
402}
403
404void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight)
405{
406    // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
407    // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
408    // function to take ints causes various internal mismatches. But selectionRect takes ints, and
409    // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
410    // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
411    ASSERT(end == UINT_MAX || end <= INT_MAX);
412    ASSERT(start <= INT_MAX);
413    start = min(start, static_cast<unsigned>(INT_MAX));
414    end = min(end, static_cast<unsigned>(INT_MAX));
415
416    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
417        // Note: box->end() returns the index of the last character, not the index past it
418        if (start <= box->start() && box->end() < end) {
419            IntRect r(box->calculateBoundaries());
420            if (useSelectionHeight) {
421                IntRect selectionRect = box->selectionRect(0, 0, start, end);
422                if (box->isHorizontal()) {
423                    r.setHeight(selectionRect.height());
424                    r.setY(selectionRect.y());
425                } else {
426                    r.setWidth(selectionRect.width());
427                    r.setX(selectionRect.x());
428                }
429            }
430            quads.append(localToAbsoluteQuad(FloatRect(r)));
431        } else {
432            unsigned realEnd = min(box->end() + 1, end);
433            IntRect r = box->selectionRect(0, 0, start, realEnd);
434            if (r.height()) {
435                if (!useSelectionHeight) {
436                    // change the height and y position because selectionRect uses selection-specific values
437                    if (box->isHorizontal()) {
438                        r.setHeight(box->logicalHeight());
439                        r.setY(box->y());
440                    } else {
441                        r.setWidth(box->logicalHeight());
442                        r.setX(box->x());
443                    }
444                }
445                quads.append(localToAbsoluteQuad(FloatRect(r)));
446            }
447        }
448    }
449}
450
451InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const
452{
453    // The text runs point to parts of the RenderText's m_text
454    // (they don't include '\n')
455    // Find the text run that includes the character at offset
456    // and return pos, which is the position of the char in the run.
457
458    if (!m_firstTextBox)
459        return 0;
460
461    InlineTextBox* s = m_firstTextBox;
462    int off = s->len();
463    while (offset > off && s->nextTextBox()) {
464        s = s->nextTextBox();
465        off = s->start() + s->len();
466    }
467    // we are now in the correct text run
468    pos = (offset > off ? s->len() : s->len() - (off - offset) );
469    return s;
470}
471
472VisiblePosition RenderText::positionForPoint(const IntPoint& point)
473{
474    if (!firstTextBox() || textLength() == 0)
475        return createVisiblePosition(0, DOWNSTREAM);
476
477    // Get the offset for the position, since this will take rtl text into account.
478    int offset;
479
480    int pointLineDirection = firstTextBox()->isHorizontal() ? point.x() : point.y();
481    int pointBlockDirection = firstTextBox()->isHorizontal() ? point.y() : point.x();
482
483    // FIXME: We should be able to roll these special cases into the general cases in the loop below.
484    if (firstTextBox() && pointBlockDirection <  firstTextBox()->root()->selectionBottom() && pointLineDirection < firstTextBox()->logicalLeft()) {
485        // at the y coordinate of the first line or above
486        // and the x coordinate is to the left of the first text box left edge
487        offset = firstTextBox()->offsetForPosition(pointLineDirection);
488        return createVisiblePosition(offset + firstTextBox()->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
489    }
490    if (lastTextBox() && pointBlockDirection >= lastTextBox()->root()->selectionTop() && pointLineDirection >= lastTextBox()->logicalRight()) {
491        // at the y coordinate of the last line or below
492        // and the x coordinate is to the right of the last text box right edge
493        offset = lastTextBox()->offsetForPosition(pointLineDirection);
494        return createVisiblePosition(offset + lastTextBox()->start(), VP_UPSTREAM_IF_POSSIBLE);
495    }
496
497    InlineTextBox* lastBoxAbove = 0;
498    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
499        RootInlineBox* rootBox = box->root();
500        if (pointBlockDirection >= rootBox->selectionTop()) {
501            int bottom = rootBox->selectionBottom();
502            if (rootBox->nextRootBox())
503                bottom = min(bottom, rootBox->nextRootBox()->lineTop());
504            if (pointBlockDirection < bottom) {
505                offset = box->offsetForPosition(pointLineDirection);
506
507                if (pointLineDirection == box->logicalLeft())
508                    // the x coordinate is equal to the left edge of this box
509                    // the affinity must be downstream so the position doesn't jump back to the previous line
510                    return createVisiblePosition(offset + box->start(), DOWNSTREAM);
511
512                if (pointLineDirection < box->logicalRight())
513                    // and the x coordinate is to the left of the right edge of this box
514                    // check to see if position goes in this box
515                    return createVisiblePosition(offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
516
517                if (!box->prevOnLine() && pointLineDirection < box->logicalLeft())
518                    // box is first on line
519                    // and the x coordinate is to the left of the first text box left edge
520                    return createVisiblePosition(offset + box->start(), DOWNSTREAM);
521
522                if (!box->nextOnLine())
523                    // box is last on line
524                    // and the x coordinate is to the right of the last text box right edge
525                    // generate VisiblePosition, use UPSTREAM affinity if possible
526                    return createVisiblePosition(offset + box->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
527            }
528            lastBoxAbove = box;
529        }
530    }
531
532    return createVisiblePosition(lastBoxAbove ? lastBoxAbove->start() + lastBoxAbove->len() : 0, DOWNSTREAM);
533}
534
535IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
536{
537    if (!inlineBox)
538        return IntRect();
539
540    ASSERT(inlineBox->isInlineTextBox());
541    if (!inlineBox->isInlineTextBox())
542        return IntRect();
543
544    InlineTextBox* box = static_cast<InlineTextBox*>(inlineBox);
545
546    int height = box->root()->selectionHeight();
547    int top = box->root()->selectionTop();
548
549    // Go ahead and round left to snap it to the nearest pixel.
550    float left = box->positionForOffset(caretOffset);
551
552    // Distribute the caret's width to either side of the offset.
553    int caretWidthLeftOfOffset = caretWidth / 2;
554    left -= caretWidthLeftOfOffset;
555    int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset;
556
557    left = roundf(left);
558
559    float rootLeft = box->root()->logicalLeft();
560    float rootRight = box->root()->logicalRight();
561
562    // FIXME: should we use the width of the root inline box or the
563    // width of the containing block for this?
564    if (extraWidthToEndOfLine)
565        *extraWidthToEndOfLine = (box->root()->logicalWidth() + rootLeft) - (left + 1);
566
567    RenderBlock* cb = containingBlock();
568    RenderStyle* cbStyle = cb->style();
569    float leftEdge;
570    float rightEdge;
571    if (style()->autoWrap()) {
572        leftEdge = cb->logicalLeft();
573        rightEdge = cb->logicalRight();
574    } else {
575        leftEdge = min(static_cast<float>(cb->logicalLeft()), rootLeft);
576        rightEdge = max(static_cast<float>(cb->logicalRight()), rootRight);
577    }
578
579    bool rightAligned = false;
580    switch (cbStyle->textAlign()) {
581    case TAAUTO:
582    case JUSTIFY:
583        rightAligned = !cbStyle->isLeftToRightDirection();
584        break;
585    case RIGHT:
586    case WEBKIT_RIGHT:
587        rightAligned = true;
588        break;
589    case LEFT:
590    case WEBKIT_LEFT:
591    case CENTER:
592    case WEBKIT_CENTER:
593        break;
594    case TASTART:
595        rightAligned = !cbStyle->isLeftToRightDirection();
596        break;
597    case TAEND:
598        rightAligned = cbStyle->isLeftToRightDirection();
599        break;
600    }
601
602    if (rightAligned) {
603        left = max(left, leftEdge);
604        left = min(left, rootRight - caretWidth);
605    } else {
606        left = min(left, rightEdge - caretWidthRightOfOffset);
607        left = max(left, rootLeft);
608    }
609
610    return style()->isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth);
611}
612
613ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
614{
615    if (style()->hasTextCombine() && isCombineText()) {
616        const RenderCombineText* combineText = toRenderCombineText(this);
617        if (combineText->isCombined())
618            return combineText->combinedTextWidth(f);
619    }
620
621    if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
622        float monospaceCharacterWidth = f.spaceWidth();
623        float tabWidth = allowTabs() ? monospaceCharacterWidth * 8 : 0;
624        float w = 0;
625        bool isSpace;
626        bool previousCharWasSpace = true; // FIXME: Preserves historical behavior, but seems wrong for start > 0.
627        ASSERT(m_text);
628        StringImpl& text = *m_text.impl();
629        for (int i = start; i < start + len; i++) {
630            char c = text[i];
631            if (c <= ' ') {
632                if (c == ' ' || c == '\n') {
633                    w += monospaceCharacterWidth;
634                    isSpace = true;
635                } else if (c == '\t') {
636                    w += tabWidth ? tabWidth - fmodf(xPos + w, tabWidth) : monospaceCharacterWidth;
637                    isSpace = true;
638                } else
639                    isSpace = false;
640            } else {
641                w += monospaceCharacterWidth;
642                isSpace = false;
643            }
644            if (isSpace && !previousCharWasSpace)
645                w += f.wordSpacing();
646            previousCharWasSpace = isSpace;
647        }
648        return w;
649    }
650
651    return f.width(TextRun(text()->characters() + start, len, allowTabs(), xPos), fallbackFonts, glyphOverflow);
652}
653
654void RenderText::trimmedPrefWidths(float leadWidth,
655                                   float& beginMinW, bool& beginWS,
656                                   float& endMinW, bool& endWS,
657                                   bool& hasBreakableChar, bool& hasBreak,
658                                   float& beginMaxW, float& endMaxW,
659                                   float& minW, float& maxW, bool& stripFrontSpaces)
660{
661    bool collapseWhiteSpace = style()->collapseWhiteSpace();
662    if (!collapseWhiteSpace)
663        stripFrontSpaces = false;
664
665    if (m_hasTab || preferredLogicalWidthsDirty())
666        computePreferredLogicalWidths(leadWidth);
667
668    beginWS = !stripFrontSpaces && m_hasBeginWS;
669    endWS = m_hasEndWS;
670
671    int len = textLength();
672
673    if (!len || (stripFrontSpaces && text()->containsOnlyWhitespace())) {
674        beginMinW = 0;
675        endMinW = 0;
676        beginMaxW = 0;
677        endMaxW = 0;
678        minW = 0;
679        maxW = 0;
680        hasBreak = false;
681        return;
682    }
683
684    minW = m_minWidth;
685    maxW = m_maxWidth;
686
687    beginMinW = m_beginMinWidth;
688    endMinW = m_endMinWidth;
689
690    hasBreakableChar = m_hasBreakableChar;
691    hasBreak = m_hasBreak;
692
693    ASSERT(m_text);
694    StringImpl& text = *m_text.impl();
695    if (text[0] == ' ' || (text[0] == '\n' && !style()->preserveNewline()) || text[0] == '\t') {
696        const Font& f = style()->font(); // FIXME: This ignores first-line.
697        if (stripFrontSpaces) {
698            const UChar space = ' ';
699            float spaceWidth = f.width(TextRun(&space, 1));
700            maxW -= spaceWidth;
701        } else
702            maxW += f.wordSpacing();
703    }
704
705    stripFrontSpaces = collapseWhiteSpace && m_hasEndWS;
706
707    if (!style()->autoWrap() || minW > maxW)
708        minW = maxW;
709
710    // Compute our max widths by scanning the string for newlines.
711    if (hasBreak) {
712        const Font& f = style()->font(); // FIXME: This ignores first-line.
713        bool firstLine = true;
714        beginMaxW = maxW;
715        endMaxW = maxW;
716        for (int i = 0; i < len; i++) {
717            int linelen = 0;
718            while (i + linelen < len && text[i + linelen] != '\n')
719                linelen++;
720
721            if (linelen) {
722                endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW, 0, 0);
723                if (firstLine) {
724                    firstLine = false;
725                    leadWidth = 0;
726                    beginMaxW = endMaxW;
727                }
728                i += linelen;
729            } else if (firstLine) {
730                beginMaxW = 0;
731                firstLine = false;
732                leadWidth = 0;
733            }
734
735            if (i == len - 1)
736                // A <pre> run that ends with a newline, as in, e.g.,
737                // <pre>Some text\n\n<span>More text</pre>
738                endMaxW = 0;
739        }
740    }
741}
742
743static inline bool isSpaceAccordingToStyle(UChar c, RenderStyle* style)
744{
745    return c == ' ' || (c == noBreakSpace && style->nbspMode() == SPACE);
746}
747
748float RenderText::minLogicalWidth() const
749{
750    if (preferredLogicalWidthsDirty())
751        const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
752
753    return m_minWidth;
754}
755
756float RenderText::maxLogicalWidth() const
757{
758    if (preferredLogicalWidthsDirty())
759        const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
760
761    return m_maxWidth;
762}
763
764void RenderText::computePreferredLogicalWidths(float leadWidth)
765{
766    HashSet<const SimpleFontData*> fallbackFonts;
767    GlyphOverflow glyphOverflow;
768    computePreferredLogicalWidths(leadWidth, fallbackFonts, glyphOverflow);
769    if (fallbackFonts.isEmpty() && !glyphOverflow.left && !glyphOverflow.right && !glyphOverflow.top && !glyphOverflow.bottom)
770        m_knownToHaveNoOverflowAndNoFallbackFonts = true;
771}
772
773void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
774{
775    ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts);
776
777    m_minWidth = 0;
778    m_beginMinWidth = 0;
779    m_endMinWidth = 0;
780    m_maxWidth = 0;
781
782    if (isBR())
783        return;
784
785    float currMinWidth = 0;
786    float currMaxWidth = 0;
787    m_hasBreakableChar = false;
788    m_hasBreak = false;
789    m_hasTab = false;
790    m_hasBeginWS = false;
791    m_hasEndWS = false;
792
793    const Font& f = style()->font(); // FIXME: This ignores first-line.
794    float wordSpacing = style()->wordSpacing();
795    int len = textLength();
796    const UChar* txt = characters();
797    LazyLineBreakIterator breakIterator(txt, len);
798    bool needsWordSpacing = false;
799    bool ignoringSpaces = false;
800    bool isSpace = false;
801    bool firstWord = true;
802    bool firstLine = true;
803    int nextBreakable = -1;
804    int lastWordBoundary = 0;
805
806    int firstGlyphLeftOverflow = -1;
807
808    bool breakNBSP = style()->autoWrap() && style()->nbspMode() == SPACE;
809    bool breakAll = (style()->wordBreak() == BreakAllWordBreak || style()->wordBreak() == BreakWordBreak) && style()->autoWrap();
810
811    for (int i = 0; i < len; i++) {
812        UChar c = txt[i];
813
814        bool previousCharacterIsSpace = isSpace;
815
816        bool isNewline = false;
817        if (c == '\n') {
818            if (style()->preserveNewline()) {
819                m_hasBreak = true;
820                isNewline = true;
821                isSpace = false;
822            } else
823                isSpace = true;
824        } else if (c == '\t') {
825            if (!style()->collapseWhiteSpace()) {
826                m_hasTab = true;
827                isSpace = false;
828            } else
829                isSpace = true;
830        } else
831            isSpace = c == ' ';
832
833        if ((isSpace || isNewline) && !i)
834            m_hasBeginWS = true;
835        if ((isSpace || isNewline) && i == len - 1)
836            m_hasEndWS = true;
837
838        if (!ignoringSpaces && style()->collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
839            ignoringSpaces = true;
840
841        if (ignoringSpaces && !isSpace)
842            ignoringSpaces = false;
843
844        // Ignore spaces and soft hyphens
845        if (ignoringSpaces) {
846            ASSERT(lastWordBoundary == i);
847            lastWordBoundary++;
848            continue;
849        } else if (c == softHyphen) {
850            currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
851            if (firstGlyphLeftOverflow < 0)
852                firstGlyphLeftOverflow = glyphOverflow.left;
853            lastWordBoundary = i + 1;
854            continue;
855        }
856
857        bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable, breakNBSP);
858        bool betweenWords = true;
859        int j = i;
860        while (c != '\n' && !isSpaceAccordingToStyle(c, style()) && c != '\t' && c != softHyphen) {
861            j++;
862            if (j == len)
863                break;
864            c = txt[j];
865            if (isBreakable(breakIterator, j, nextBreakable, breakNBSP))
866                break;
867            if (breakAll) {
868                betweenWords = false;
869                break;
870            }
871        }
872
873        int wordLen = j - i;
874        if (wordLen) {
875            float w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
876            if (firstGlyphLeftOverflow < 0)
877                firstGlyphLeftOverflow = glyphOverflow.left;
878            currMinWidth += w;
879            if (betweenWords) {
880                if (lastWordBoundary == i)
881                    currMaxWidth += w;
882                else
883                    currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
884                lastWordBoundary = j;
885            }
886
887            bool isSpace = (j < len) && isSpaceAccordingToStyle(c, style());
888            bool isCollapsibleWhiteSpace = (j < len) && style()->isCollapsibleWhiteSpace(c);
889            if (j < len && style()->autoWrap())
890                m_hasBreakableChar = true;
891
892            // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
893            // last word in the run.
894            if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
895                currMaxWidth += wordSpacing;
896
897            if (firstWord) {
898                firstWord = false;
899                // If the first character in the run is breakable, then we consider ourselves to have a beginning
900                // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
901                // being appended to a previous text run when considering the total minimum width of the containing block.
902                if (hasBreak)
903                    m_hasBreakableChar = true;
904                m_beginMinWidth = hasBreak ? 0 : w;
905            }
906            m_endMinWidth = w;
907
908            if (currMinWidth > m_minWidth)
909                m_minWidth = currMinWidth;
910            currMinWidth = 0;
911
912            i += wordLen - 1;
913        } else {
914            // Nowrap can never be broken, so don't bother setting the
915            // breakable character boolean. Pre can only be broken if we encounter a newline.
916            if (style()->autoWrap() || isNewline)
917                m_hasBreakableChar = true;
918
919            if (currMinWidth > m_minWidth)
920                m_minWidth = currMinWidth;
921            currMinWidth = 0;
922
923            if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
924                if (firstLine) {
925                    firstLine = false;
926                    leadWidth = 0;
927                    if (!style()->autoWrap())
928                        m_beginMinWidth = currMaxWidth;
929                }
930
931                if (currMaxWidth > m_maxWidth)
932                    m_maxWidth = currMaxWidth;
933                currMaxWidth = 0;
934            } else {
935                currMaxWidth += f.width(TextRun(txt + i, 1, allowTabs(), leadWidth + currMaxWidth));
936                glyphOverflow.right = 0;
937                needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
938            }
939            ASSERT(lastWordBoundary == i);
940            lastWordBoundary++;
941        }
942    }
943
944    if (firstGlyphLeftOverflow > 0)
945        glyphOverflow.left = firstGlyphLeftOverflow;
946
947    if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord))
948        currMaxWidth += wordSpacing;
949
950    m_minWidth = max(currMinWidth, m_minWidth);
951    m_maxWidth = max(currMaxWidth, m_maxWidth);
952
953    if (!style()->autoWrap())
954        m_minWidth = m_maxWidth;
955
956    if (style()->whiteSpace() == PRE) {
957        if (firstLine)
958            m_beginMinWidth = m_maxWidth;
959        m_endMinWidth = currMaxWidth;
960    }
961
962    setPreferredLogicalWidthsDirty(false);
963}
964
965bool RenderText::isAllCollapsibleWhitespace()
966{
967    int length = textLength();
968    const UChar* text = characters();
969    for (int i = 0; i < length; i++) {
970        if (!style()->isCollapsibleWhiteSpace(text[i]))
971            return false;
972    }
973    return true;
974}
975
976bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
977{
978    ASSERT(m_text);
979    StringImpl& text = *m_text.impl();
980    unsigned currPos;
981    for (currPos = from;
982         currPos < from + len && (text[currPos] == '\n' || text[currPos] == ' ' || text[currPos] == '\t');
983         currPos++) { }
984    return currPos >= (from + len);
985}
986
987FloatPoint RenderText::firstRunOrigin() const
988{
989    return IntPoint(firstRunX(), firstRunY());
990}
991
992float RenderText::firstRunX() const
993{
994    return m_firstTextBox ? m_firstTextBox->m_x : 0;
995}
996
997float RenderText::firstRunY() const
998{
999    return m_firstTextBox ? m_firstTextBox->m_y : 0;
1000}
1001
1002void RenderText::setSelectionState(SelectionState state)
1003{
1004    InlineTextBox* box;
1005
1006    RenderObject::setSelectionState(state);
1007    if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) {
1008        int startPos, endPos;
1009        selectionStartEnd(startPos, endPos);
1010        if (selectionState() == SelectionStart) {
1011            endPos = textLength();
1012
1013            // to handle selection from end of text to end of line
1014            if (startPos != 0 && startPos == endPos)
1015                startPos = endPos - 1;
1016        } else if (selectionState() == SelectionEnd)
1017            startPos = 0;
1018
1019        for (box = firstTextBox(); box; box = box->nextTextBox()) {
1020            if (box->isSelected(startPos, endPos)) {
1021                RootInlineBox* line = box->root();
1022                if (line)
1023                    line->setHasSelectedChildren(true);
1024            }
1025        }
1026    } else {
1027        for (box = firstTextBox(); box; box = box->nextTextBox()) {
1028            RootInlineBox* line = box->root();
1029            if (line)
1030                line->setHasSelectedChildren(state == SelectionInside);
1031        }
1032    }
1033
1034    // The returned value can be null in case of an orphaned tree.
1035    if (RenderBlock* cb = containingBlock())
1036        cb->setSelectionState(state);
1037}
1038
1039void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force)
1040{
1041    unsigned oldLen = textLength();
1042    unsigned newLen = text->length();
1043    int delta = newLen - oldLen;
1044    unsigned end = len ? offset + len - 1 : offset;
1045
1046    RootInlineBox* firstRootBox = 0;
1047    RootInlineBox* lastRootBox = 0;
1048
1049    bool dirtiedLines = false;
1050
1051    // Dirty all text boxes that include characters in between offset and offset+len.
1052    for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1053        // Text run is entirely before the affected range.
1054        if (curr->end() < offset)
1055            continue;
1056
1057        // Text run is entirely after the affected range.
1058        if (curr->start() > end) {
1059            curr->offsetRun(delta);
1060            RootInlineBox* root = curr->root();
1061            if (!firstRootBox) {
1062                firstRootBox = root;
1063                if (!dirtiedLines) {
1064                    // The affected area was in between two runs. Go ahead and mark the root box of
1065                    // the run after the affected area as dirty.
1066                    firstRootBox->markDirty();
1067                    dirtiedLines = true;
1068                }
1069            }
1070            lastRootBox = root;
1071        } else if (curr->end() >= offset && curr->end() <= end) {
1072            // Text run overlaps with the left end of the affected range.
1073            curr->dirtyLineBoxes();
1074            dirtiedLines = true;
1075        } else if (curr->start() <= offset && curr->end() >= end) {
1076            // Text run subsumes the affected range.
1077            curr->dirtyLineBoxes();
1078            dirtiedLines = true;
1079        } else if (curr->start() <= end && curr->end() >= end) {
1080            // Text run overlaps with right end of the affected range.
1081            curr->dirtyLineBoxes();
1082            dirtiedLines = true;
1083        }
1084    }
1085
1086    // Now we have to walk all of the clean lines and adjust their cached line break information
1087    // to reflect our updated offsets.
1088    if (lastRootBox)
1089        lastRootBox = lastRootBox->nextRootBox();
1090    if (firstRootBox) {
1091        RootInlineBox* prev = firstRootBox->prevRootBox();
1092        if (prev)
1093            firstRootBox = prev;
1094    } else if (lastTextBox()) {
1095        ASSERT(!lastRootBox);
1096        firstRootBox = lastTextBox()->root();
1097        firstRootBox->markDirty();
1098        dirtiedLines = true;
1099    }
1100    for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
1101        if (curr->lineBreakObj() == this && curr->lineBreakPos() > end)
1102            curr->setLineBreakPos(curr->lineBreakPos() + delta);
1103    }
1104
1105    // If the text node is empty, dirty the line where new text will be inserted.
1106    if (!firstTextBox() && parent()) {
1107        parent()->dirtyLinesFromChangedChild(this);
1108        dirtiedLines = true;
1109    }
1110
1111    m_linesDirty = dirtiedLines;
1112    setText(text, force);
1113}
1114
1115static inline bool isInlineFlowOrEmptyText(const RenderObject* o)
1116{
1117    if (o->isRenderInline())
1118        return true;
1119    if (!o->isText())
1120        return false;
1121    StringImpl* text = toRenderText(o)->text();
1122    if (!text)
1123        return true;
1124    return !text->length();
1125}
1126
1127UChar RenderText::previousCharacter() const
1128{
1129    // find previous text renderer if one exists
1130    const RenderObject* previousText = this;
1131    while ((previousText = previousText->previousInPreOrder()))
1132        if (!isInlineFlowOrEmptyText(previousText))
1133            break;
1134    UChar prev = ' ';
1135    if (previousText && previousText->isText())
1136        if (StringImpl* previousString = toRenderText(previousText)->text())
1137            prev = (*previousString)[previousString->length() - 1];
1138    return prev;
1139}
1140
1141void RenderText::transformText(String& text) const
1142{
1143    ASSERT(style());
1144    switch (style()->textTransform()) {
1145    case TTNONE:
1146        break;
1147    case CAPITALIZE:
1148        makeCapitalized(&text, previousCharacter());
1149        break;
1150    case UPPERCASE:
1151        text.makeUpper();
1152        break;
1153    case LOWERCASE:
1154        text.makeLower();
1155        break;
1156    }
1157}
1158
1159void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
1160{
1161    ASSERT(text);
1162    m_text = text;
1163    if (m_needsTranscoding) {
1164        const TextEncoding* encoding = document()->decoder() ? &document()->decoder()->encoding() : 0;
1165        fontTranscoder().convert(m_text, style()->font().fontDescription(), encoding);
1166    }
1167    ASSERT(m_text);
1168
1169    if (style()) {
1170        transformText(m_text);
1171
1172        // We use the same characters here as for list markers.
1173        // See the listMarkerText function in RenderListMarker.cpp.
1174        switch (style()->textSecurity()) {
1175        case TSNONE:
1176            break;
1177        case TSCIRCLE:
1178            secureText(whiteBullet);
1179            break;
1180        case TSDISC:
1181            secureText(bullet);
1182            break;
1183        case TSSQUARE:
1184            secureText(blackSquare);
1185        }
1186    }
1187
1188    ASSERT(m_text);
1189    ASSERT(!isBR() || (textLength() == 1 && m_text[0] == '\n'));
1190
1191    m_isAllASCII = m_text.containsOnlyASCII();
1192}
1193
1194void RenderText::secureText(UChar mask)
1195{
1196    if (!m_text.length())
1197        return;
1198
1199    int lastTypedCharacterOffsetToReveal = -1;
1200    String revealedText;
1201    SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->get(this) : 0;
1202    if (secureTextTimer && secureTextTimer->isActive()) {
1203        lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOffset();
1204        if (lastTypedCharacterOffsetToReveal >= 0)
1205            revealedText.append(m_text[lastTypedCharacterOffsetToReveal]);
1206    }
1207
1208    m_text.makeSecure(mask);
1209    if (lastTypedCharacterOffsetToReveal >= 0) {
1210        m_text.replace(lastTypedCharacterOffsetToReveal, 1, revealedText);
1211        // m_text may be updated later before timer fires. We invalidate the lastTypedCharacterOffset to avoid inconsistency.
1212        secureTextTimer->invalidate();
1213    }
1214}
1215
1216void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
1217{
1218    ASSERT(text);
1219
1220    if (!force && equal(m_text.impl(), text.get()))
1221        return;
1222
1223    setTextInternal(text);
1224    setNeedsLayoutAndPrefWidthsRecalc();
1225    m_knownToHaveNoOverflowAndNoFallbackFonts = false;
1226
1227    AXObjectCache* axObjectCache = document()->axObjectCache();
1228    if (axObjectCache->accessibilityEnabled())
1229        axObjectCache->contentChanged(this);
1230}
1231
1232String RenderText::textWithoutTranscoding() const
1233{
1234    // If m_text isn't transcoded or is secure, we can just return the modified text.
1235    if (!m_needsTranscoding || style()->textSecurity() != TSNONE)
1236        return text();
1237
1238    // Otherwise, we should use original text. If text-transform is
1239    // specified, we should transform the text on the fly.
1240    String text = originalText();
1241    if (style())
1242        transformText(text);
1243    return text;
1244}
1245
1246void RenderText::dirtyLineBoxes(bool fullLayout)
1247{
1248    if (fullLayout)
1249        deleteTextBoxes();
1250    else if (!m_linesDirty) {
1251        for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1252            box->dirtyLineBoxes();
1253    }
1254    m_linesDirty = false;
1255}
1256
1257InlineTextBox* RenderText::createTextBox()
1258{
1259    return new (renderArena()) InlineTextBox(this);
1260}
1261
1262InlineTextBox* RenderText::createInlineTextBox()
1263{
1264    InlineTextBox* textBox = createTextBox();
1265    if (!m_firstTextBox)
1266        m_firstTextBox = m_lastTextBox = textBox;
1267    else {
1268        m_lastTextBox->setNextTextBox(textBox);
1269        textBox->setPreviousTextBox(m_lastTextBox);
1270        m_lastTextBox = textBox;
1271    }
1272    textBox->setIsText(true);
1273    return textBox;
1274}
1275
1276void RenderText::positionLineBox(InlineBox* box)
1277{
1278    InlineTextBox* s = static_cast<InlineTextBox*>(box);
1279
1280    // FIXME: should not be needed!!!
1281    if (!s->len()) {
1282        // We want the box to be destroyed.
1283        s->remove();
1284        if (m_firstTextBox == s)
1285            m_firstTextBox = s->nextTextBox();
1286        else
1287            s->prevTextBox()->setNextTextBox(s->nextTextBox());
1288        if (m_lastTextBox == s)
1289            m_lastTextBox = s->prevTextBox();
1290        else
1291            s->nextTextBox()->setPreviousTextBox(s->prevTextBox());
1292        s->destroy(renderArena());
1293        return;
1294    }
1295
1296    m_containsReversedText |= !s->isLeftToRightDirection();
1297}
1298
1299float RenderText::width(unsigned from, unsigned len, float xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1300{
1301    if (from >= textLength())
1302        return 0;
1303
1304    if (from + len > textLength())
1305        len = textLength() - from;
1306
1307    return width(from, len, style(firstLine)->font(), xPos, fallbackFonts, glyphOverflow);
1308}
1309
1310float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1311{
1312    ASSERT(from + len <= textLength());
1313    if (!characters())
1314        return 0;
1315
1316    float w;
1317    if (&f == &style()->font()) {
1318        if (!style()->preserveNewline() && !from && len == textLength() && (!glyphOverflow || !glyphOverflow->computeBounds)) {
1319            if (fallbackFonts) {
1320                ASSERT(glyphOverflow);
1321                if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
1322                    const_cast<RenderText*>(this)->computePreferredLogicalWidths(0, *fallbackFonts, *glyphOverflow);
1323                    if (fallbackFonts->isEmpty() && !glyphOverflow->left && !glyphOverflow->right && !glyphOverflow->top && !glyphOverflow->bottom)
1324                        m_knownToHaveNoOverflowAndNoFallbackFonts = true;
1325                }
1326                w = m_maxWidth;
1327            } else
1328                w = maxLogicalWidth();
1329        } else
1330            w = widthFromCache(f, from, len, xPos, fallbackFonts, glyphOverflow);
1331    } else
1332        w = f.width(TextRun(text()->characters() + from, len, allowTabs(), xPos), fallbackFonts, glyphOverflow);
1333
1334    return w;
1335}
1336
1337IntRect RenderText::linesBoundingBox() const
1338{
1339    IntRect result;
1340
1341    ASSERT(!firstTextBox() == !lastTextBox());  // Either both are null or both exist.
1342    if (firstTextBox() && lastTextBox()) {
1343        // Return the width of the minimal left side and the maximal right side.
1344        float logicalLeftSide = 0;
1345        float logicalRightSide = 0;
1346        for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1347            if (curr == firstTextBox() || curr->logicalLeft() < logicalLeftSide)
1348                logicalLeftSide = curr->logicalLeft();
1349            if (curr == firstTextBox() || curr->logicalRight() > logicalRightSide)
1350                logicalRightSide = curr->logicalRight();
1351        }
1352
1353        bool isHorizontal = style()->isHorizontalWritingMode();
1354
1355        float x = isHorizontal ? logicalLeftSide : firstTextBox()->x();
1356        float y = isHorizontal ? firstTextBox()->y() : logicalLeftSide;
1357        float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTextBox()->logicalBottom() - x;
1358        float height = isHorizontal ? lastTextBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
1359        result = enclosingIntRect(FloatRect(x, y, width, height));
1360    }
1361
1362    return result;
1363}
1364
1365IntRect RenderText::linesVisualOverflowBoundingBox() const
1366{
1367    if (!firstTextBox())
1368        return IntRect();
1369
1370    // Return the width of the minimal left side and the maximal right side.
1371    int logicalLeftSide = numeric_limits<int>::max();
1372    int logicalRightSide = numeric_limits<int>::min();
1373    for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1374        logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
1375        logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
1376    }
1377
1378    int logicalTop = firstTextBox()->logicalTopVisualOverflow();
1379    int logicalWidth = logicalRightSide - logicalLeftSide;
1380    int logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - logicalTop;
1381
1382    IntRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
1383    if (!style()->isHorizontalWritingMode())
1384        rect = rect.transposedRect();
1385    return rect;
1386}
1387
1388IntRect RenderText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
1389{
1390    bool repaintContainerSkipped;
1391    RenderObject* container = this->container(repaintContainer, &repaintContainerSkipped);
1392    // The container may be an ancestor of repaintContainer, but we need to do a repaintContainer-relative repaint.
1393    if (repaintContainerSkipped)
1394        return repaintContainer->clippedOverflowRectForRepaint(repaintContainer);
1395
1396    return container->clippedOverflowRectForRepaint(repaintContainer);
1397}
1398
1399IntRect RenderText::selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent)
1400{
1401    ASSERT(!needsLayout());
1402
1403    if (selectionState() == SelectionNone)
1404        return IntRect();
1405    RenderBlock* cb = containingBlock();
1406    if (!cb)
1407        return IntRect();
1408
1409    // Now calculate startPos and endPos for painting selection.
1410    // We include a selection while endPos > 0
1411    int startPos, endPos;
1412    if (selectionState() == SelectionInside) {
1413        // We are fully selected.
1414        startPos = 0;
1415        endPos = textLength();
1416    } else {
1417        selectionStartEnd(startPos, endPos);
1418        if (selectionState() == SelectionStart)
1419            endPos = textLength();
1420        else if (selectionState() == SelectionEnd)
1421            startPos = 0;
1422    }
1423
1424    if (startPos == endPos)
1425        return IntRect();
1426
1427    IntRect rect;
1428    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1429        rect.unite(box->selectionRect(0, 0, startPos, endPos));
1430        rect.unite(ellipsisRectForBox(box, startPos, endPos));
1431    }
1432
1433    if (clipToVisibleContent)
1434        computeRectForRepaint(repaintContainer, rect);
1435    else {
1436        if (cb->hasColumns())
1437            cb->adjustRectForColumns(rect);
1438
1439        rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox();
1440    }
1441
1442    return rect;
1443}
1444
1445int RenderText::caretMinOffset() const
1446{
1447    InlineTextBox* box = firstTextBox();
1448    if (!box)
1449        return 0;
1450    int minOffset = box->start();
1451    for (box = box->nextTextBox(); box; box = box->nextTextBox())
1452        minOffset = min<int>(minOffset, box->start());
1453    return minOffset;
1454}
1455
1456int RenderText::caretMaxOffset() const
1457{
1458    InlineTextBox* box = lastTextBox();
1459    if (!box)
1460        return textLength();
1461    int maxOffset = box->start() + box->len();
1462    for (box = box->prevTextBox(); box; box = box->prevTextBox())
1463        maxOffset = max<int>(maxOffset, box->start() + box->len());
1464    return maxOffset;
1465}
1466
1467unsigned RenderText::caretMaxRenderedOffset() const
1468{
1469    int l = 0;
1470    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1471        l += box->len();
1472    return l;
1473}
1474
1475int RenderText::previousOffset(int current) const
1476{
1477    StringImpl* si = m_text.impl();
1478    TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length());
1479    if (!iterator)
1480        return current - 1;
1481
1482    long result = textBreakPreceding(iterator, current);
1483    if (result == TextBreakDone)
1484        result = current - 1;
1485
1486#ifdef BUILDING_ON_TIGER
1487    // ICU 3.2 allows character breaks before a half-width Katakana voiced mark.
1488    if (static_cast<unsigned>(result) < si->length()) {
1489        UChar character = (*si)[result];
1490        if (character == 0xFF9E || character == 0xFF9F)
1491            --result;
1492    }
1493#endif
1494
1495    return result;
1496}
1497
1498#if PLATFORM(MAC)
1499
1500#define HANGUL_CHOSEONG_START (0x1100)
1501#define HANGUL_CHOSEONG_END (0x115F)
1502#define HANGUL_JUNGSEONG_START (0x1160)
1503#define HANGUL_JUNGSEONG_END (0x11A2)
1504#define HANGUL_JONGSEONG_START (0x11A8)
1505#define HANGUL_JONGSEONG_END (0x11F9)
1506#define HANGUL_SYLLABLE_START (0xAC00)
1507#define HANGUL_SYLLABLE_END (0xD7AF)
1508#define HANGUL_JONGSEONG_COUNT (28)
1509
1510enum HangulState {
1511    HangulStateL,
1512    HangulStateV,
1513    HangulStateT,
1514    HangulStateLV,
1515    HangulStateLVT,
1516    HangulStateBreak
1517};
1518
1519inline bool isHangulLVT(UChar32 character)
1520{
1521    return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
1522}
1523
1524inline bool isMark(UChar32 c)
1525{
1526    int8_t charType = u_charType(c);
1527    return charType == U_NON_SPACING_MARK || charType == U_ENCLOSING_MARK || charType == U_COMBINING_SPACING_MARK;
1528}
1529
1530#endif
1531
1532int RenderText::previousOffsetForBackwardDeletion(int current) const
1533{
1534#if PLATFORM(MAC)
1535    ASSERT(m_text);
1536    StringImpl& text = *m_text.impl();
1537    UChar32 character;
1538    while (current > 0) {
1539        if (U16_IS_TRAIL(text[--current]))
1540            --current;
1541        if (current < 0)
1542            break;
1543
1544        UChar32 character = text.characterStartingAt(current);
1545
1546        // We don't combine characters in Armenian ... Limbu range for backward deletion.
1547        if ((character >= 0x0530) && (character < 0x1950))
1548            break;
1549
1550        if (!isMark(character) && (character != 0xFF9E) && (character != 0xFF9F))
1551            break;
1552    }
1553
1554    if (current <= 0)
1555        return current;
1556
1557    // Hangul
1558    character = text.characterStartingAt(current);
1559    if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) {
1560        HangulState state;
1561        HangulState initialState;
1562
1563        if (character < HANGUL_JUNGSEONG_START)
1564            state = HangulStateL;
1565        else if (character < HANGUL_JONGSEONG_START)
1566            state = HangulStateV;
1567        else if (character < HANGUL_SYLLABLE_START)
1568            state = HangulStateT;
1569        else
1570            state = isHangulLVT(character) ? HangulStateLVT : HangulStateLV;
1571
1572        initialState = state;
1573
1574        while (current > 0 && ((character = text.characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) {
1575            switch (state) {
1576            case HangulStateV:
1577                if (character <= HANGUL_CHOSEONG_END)
1578                    state = HangulStateL;
1579                else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END) && !isHangulLVT(character))
1580                    state = HangulStateLV;
1581                else if (character > HANGUL_JUNGSEONG_END)
1582                    state = HangulStateBreak;
1583                break;
1584            case HangulStateT:
1585                if ((character >= HANGUL_JUNGSEONG_START) && (character <= HANGUL_JUNGSEONG_END))
1586                    state = HangulStateV;
1587                else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))
1588                    state = (isHangulLVT(character) ? HangulStateLVT : HangulStateLV);
1589                else if (character < HANGUL_JUNGSEONG_START)
1590                    state = HangulStateBreak;
1591                break;
1592            default:
1593                state = (character < HANGUL_JUNGSEONG_START) ? HangulStateL : HangulStateBreak;
1594                break;
1595            }
1596            if (state == HangulStateBreak)
1597                break;
1598
1599            --current;
1600        }
1601    }
1602
1603    return current;
1604#else
1605    // Platforms other than Mac delete by one code point.
1606    return current - 1;
1607#endif
1608}
1609
1610int RenderText::nextOffset(int current) const
1611{
1612    StringImpl* si = m_text.impl();
1613    TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length());
1614    if (!iterator)
1615        return current + 1;
1616
1617    long result = textBreakFollowing(iterator, current);
1618    if (result == TextBreakDone)
1619        result = current + 1;
1620
1621#ifdef BUILDING_ON_TIGER
1622    // ICU 3.2 allows character breaks before a half-width Katakana voiced mark.
1623    if (static_cast<unsigned>(result) < si->length()) {
1624        UChar character = (*si)[result];
1625        if (character == 0xFF9E || character == 0xFF9F)
1626            ++result;
1627    }
1628#endif
1629
1630    return result;
1631}
1632
1633#ifndef NDEBUG
1634
1635void RenderText::checkConsistency() const
1636{
1637#ifdef CHECK_CONSISTENCY
1638    const InlineTextBox* prev = 0;
1639    for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) {
1640        ASSERT(child->renderer() == this);
1641        ASSERT(child->prevTextBox() == prev);
1642        prev = child;
1643    }
1644    ASSERT(prev == m_lastTextBox);
1645#endif
1646}
1647
1648#endif
1649
1650void RenderText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset)
1651{
1652    if (!gSecureTextTimers)
1653        gSecureTextTimers = new SecureTextTimerMap;
1654
1655    SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this);
1656    if (!secureTextTimer) {
1657        secureTextTimer = new SecureTextTimer(this);
1658        gSecureTextTimers->add(this, secureTextTimer);
1659    }
1660    secureTextTimer->restartWithNewText(lastTypedCharacterOffset);
1661}
1662
1663} // namespace WebCore
1664