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 "core/rendering/RenderText.h"
27
28#include "core/accessibility/AXObjectCache.h"
29#include "core/dom/Text.h"
30#include "core/editing/TextIterator.h"
31#include "core/frame/FrameView.h"
32#include "core/frame/Settings.h"
33#include "core/html/parser/TextResourceDecoder.h"
34#include "core/rendering/AbstractInlineTextBox.h"
35#include "core/rendering/EllipsisBox.h"
36#include "core/rendering/InlineTextBox.h"
37#include "core/rendering/RenderBlock.h"
38#include "core/rendering/RenderCombineText.h"
39#include "core/rendering/RenderLayer.h"
40#include "core/rendering/RenderView.h"
41#include "core/rendering/TextRunConstructor.h"
42#include "core/rendering/break_lines.h"
43#include "platform/fonts/Character.h"
44#include "platform/fonts/FontCache.h"
45#include "platform/geometry/FloatQuad.h"
46#include "platform/text/BidiResolver.h"
47#include "platform/text/TextBreakIterator.h"
48#include "platform/text/TextRunIterator.h"
49#include "wtf/text/StringBuffer.h"
50#include "wtf/text/StringBuilder.h"
51#include "wtf/unicode/CharacterNames.h"
52
53using namespace WTF;
54using namespace Unicode;
55
56namespace blink {
57
58struct SameSizeAsRenderText : public RenderObject {
59    uint32_t bitfields : 16;
60    float widths[4];
61    String text;
62    void* pointers[2];
63};
64
65COMPILE_ASSERT(sizeof(RenderText) == sizeof(SameSizeAsRenderText), RenderText_should_stay_small);
66
67class SecureTextTimer;
68typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap;
69static SecureTextTimerMap* gSecureTextTimers = 0;
70
71class SecureTextTimer FINAL : public TimerBase {
72public:
73    SecureTextTimer(RenderText* renderText)
74        : m_renderText(renderText)
75        , m_lastTypedCharacterOffset(-1)
76    {
77    }
78
79    void restartWithNewText(unsigned lastTypedCharacterOffset)
80    {
81        m_lastTypedCharacterOffset = lastTypedCharacterOffset;
82        if (Settings* settings = m_renderText->document().settings())
83            startOneShot(settings->passwordEchoDurationInSeconds(), FROM_HERE);
84    }
85    void invalidate() { m_lastTypedCharacterOffset = -1; }
86    unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; }
87
88private:
89    virtual void fired() OVERRIDE
90    {
91        ASSERT(gSecureTextTimers->contains(m_renderText));
92        m_renderText->setText(m_renderText->text().impl(), true /* forcing setting text as it may be masked later */);
93    }
94
95    RenderText* m_renderText;
96    int m_lastTypedCharacterOffset;
97};
98
99static void makeCapitalized(String* string, UChar previous)
100{
101    if (string->isNull())
102        return;
103
104    unsigned length = string->length();
105    const StringImpl& input = *string->impl();
106
107    if (length >= std::numeric_limits<unsigned>::max())
108        CRASH();
109
110    StringBuffer<UChar> stringWithPrevious(length + 1);
111    stringWithPrevious[0] = previous == noBreakSpace ? space : previous;
112    for (unsigned i = 1; i < length + 1; i++) {
113        // Replace &nbsp with a real space since ICU no longer treats &nbsp as a word separator.
114        if (input[i - 1] == noBreakSpace)
115            stringWithPrevious[i] = space;
116        else
117            stringWithPrevious[i] = input[i - 1];
118    }
119
120    TextBreakIterator* boundary = wordBreakIterator(stringWithPrevious.characters(), length + 1);
121    if (!boundary)
122        return;
123
124    StringBuilder result;
125    result.reserveCapacity(length);
126
127    int32_t endOfWord;
128    int32_t startOfWord = boundary->first();
129    for (endOfWord = boundary->next(); endOfWord != TextBreakDone; startOfWord = endOfWord, endOfWord = boundary->next()) {
130        if (startOfWord) // Ignore first char of previous string
131            result.append(input[startOfWord - 1] == noBreakSpace ? noBreakSpace : toTitleCase(stringWithPrevious[startOfWord]));
132        for (int i = startOfWord + 1; i < endOfWord; i++)
133            result.append(input[i - 1]);
134    }
135
136    *string = result.toString();
137}
138
139RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
140    : RenderObject(!node || node->isDocumentNode() ? 0 : node)
141    , m_hasTab(false)
142    , m_linesDirty(false)
143    , m_containsReversedText(false)
144    , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
145    , m_minWidth(-1)
146    , m_maxWidth(-1)
147    , m_firstLineMinWidth(0)
148    , m_lastLineLineMinWidth(0)
149    , m_text(str)
150    , m_firstTextBox(0)
151    , m_lastTextBox(0)
152{
153    ASSERT(m_text);
154    // FIXME: Some clients of RenderText (and subclasses) pass Document as node to create anonymous renderer.
155    // They should be switched to passing null and using setDocumentForAnonymous.
156    if (node && node->isDocumentNode())
157        setDocumentForAnonymous(toDocument(node));
158
159    m_isAllASCII = m_text.containsOnlyASCII();
160    m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
161    setIsText();
162
163    view()->frameView()->incrementVisuallyNonEmptyCharacterCount(m_text.length());
164}
165
166#if ENABLE(ASSERT)
167
168RenderText::~RenderText()
169{
170    ASSERT(!m_firstTextBox);
171    ASSERT(!m_lastTextBox);
172}
173
174#endif
175
176const char* RenderText::renderName() const
177{
178    return "RenderText";
179}
180
181bool RenderText::isTextFragment() const
182{
183    return false;
184}
185
186bool RenderText::isWordBreak() const
187{
188    return false;
189}
190
191void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
192{
193    // There is no need to ever schedule paint invalidations from a style change of a text run, since
194    // we already did this for the parent of the text run.
195    // We do have to schedule layouts, though, since a style change can force us to
196    // need to relayout.
197    if (diff.needsFullLayout()) {
198        setNeedsLayoutAndPrefWidthsRecalc();
199        m_knownToHaveNoOverflowAndNoFallbackFonts = false;
200    }
201
202    RenderStyle* newStyle = style();
203    ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
204    ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
205    if (oldTransform != newStyle->textTransform() || oldSecurity != newStyle->textSecurity())
206        transformText();
207
208    // This is an optimization that kicks off font load before layout.
209    // In order to make it fast, we only check if the first character of the
210    // text is included in the unicode ranges of the fonts.
211    if (!text().containsOnlyWhitespace())
212        newStyle->font().willUseFontData(text().characterStartingAt(0));
213}
214
215void RenderText::removeAndDestroyTextBoxes()
216{
217    if (!documentBeingDestroyed()) {
218        if (firstTextBox()) {
219            if (isBR()) {
220                RootInlineBox* next = firstTextBox()->root().nextRootBox();
221                if (next)
222                    next->markDirty();
223            }
224            for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
225                box->remove();
226        } else if (parent())
227            parent()->dirtyLinesFromChangedChild(this);
228    }
229    deleteTextBoxes();
230}
231
232void RenderText::willBeDestroyed()
233{
234    if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->take(this) : 0)
235        delete secureTextTimer;
236
237    removeAndDestroyTextBoxes();
238    RenderObject::willBeDestroyed();
239}
240
241void RenderText::extractTextBox(InlineTextBox* box)
242{
243    checkConsistency();
244
245    m_lastTextBox = box->prevTextBox();
246    if (box == m_firstTextBox)
247        m_firstTextBox = 0;
248    if (box->prevTextBox())
249        box->prevTextBox()->setNextTextBox(0);
250    box->setPreviousTextBox(0);
251    for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox())
252        curr->setExtracted();
253
254    checkConsistency();
255}
256
257void RenderText::attachTextBox(InlineTextBox* box)
258{
259    checkConsistency();
260
261    if (m_lastTextBox) {
262        m_lastTextBox->setNextTextBox(box);
263        box->setPreviousTextBox(m_lastTextBox);
264    } else
265        m_firstTextBox = box;
266    InlineTextBox* last = box;
267    for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {
268        curr->setExtracted(false);
269        last = curr;
270    }
271    m_lastTextBox = last;
272
273    checkConsistency();
274}
275
276void RenderText::removeTextBox(InlineTextBox* box)
277{
278    checkConsistency();
279
280    if (box == m_firstTextBox)
281        m_firstTextBox = box->nextTextBox();
282    if (box == m_lastTextBox)
283        m_lastTextBox = box->prevTextBox();
284    if (box->nextTextBox())
285        box->nextTextBox()->setPreviousTextBox(box->prevTextBox());
286    if (box->prevTextBox())
287        box->prevTextBox()->setNextTextBox(box->nextTextBox());
288
289    checkConsistency();
290}
291
292void RenderText::deleteTextBoxes()
293{
294    if (firstTextBox()) {
295        InlineTextBox* next;
296        for (InlineTextBox* curr = firstTextBox(); curr; curr = next) {
297            next = curr->nextTextBox();
298            curr->destroy();
299        }
300        m_firstTextBox = m_lastTextBox = 0;
301    }
302}
303
304PassRefPtr<StringImpl> RenderText::originalText() const
305{
306    Node* e = node();
307    return (e && e->isTextNode()) ? toText(e)->dataImpl() : 0;
308}
309
310String RenderText::plainText() const
311{
312    if (node())
313        return blink::plainText(rangeOfContents(node()).get());
314
315    // FIXME: this is just a stopgap until TextIterator is adapted to support generated text.
316    StringBuilder plainTextBuilder;
317    for (InlineTextBox* textBox = firstTextBox(); textBox; textBox = textBox->nextTextBox()) {
318        String text = m_text.substring(textBox->start(), textBox->len()).simplifyWhiteSpace(WTF::DoNotStripWhiteSpace);
319        plainTextBuilder.append(text);
320        if (textBox->nextTextBox() && textBox->nextTextBox()->start() > textBox->end() && text.length() && !text.right(1).containsOnlyWhitespace())
321            plainTextBuilder.append(space);
322    }
323    return plainTextBuilder.toString();
324}
325
326void RenderText::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
327{
328    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
329        rects.append(enclosingIntRect(FloatRect(accumulatedOffset + box->topLeft(), box->size())));
330}
331
332static FloatRect localQuadForTextBox(InlineTextBox* box, unsigned start, unsigned end, bool useSelectionHeight)
333{
334    unsigned realEnd = std::min(box->end() + 1, end);
335    LayoutRect r = box->localSelectionRect(start, realEnd);
336    if (r.height()) {
337        if (!useSelectionHeight) {
338            // Change the height and y position (or width and x for vertical text)
339            // because selectionRect uses selection-specific values.
340            if (box->isHorizontal()) {
341                r.setHeight(box->height());
342                r.setY(box->y());
343            } else {
344                r.setWidth(box->width());
345                r.setX(box->x());
346            }
347        }
348        return FloatRect(r);
349    }
350    return FloatRect();
351}
352
353void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
354{
355    // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
356    // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
357    // function to take ints causes various internal mismatches. But selectionRect takes ints, and
358    // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
359    // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
360    ASSERT(end == UINT_MAX || end <= INT_MAX);
361    ASSERT(start <= INT_MAX);
362    start = std::min(start, static_cast<unsigned>(INT_MAX));
363    end = std::min(end, static_cast<unsigned>(INT_MAX));
364
365    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
366        // Note: box->end() returns the index of the last character, not the index past it
367        if (start <= box->start() && box->end() < end) {
368            FloatRect r = box->calculateBoundaries();
369            if (useSelectionHeight) {
370                LayoutRect selectionRect = box->localSelectionRect(start, end);
371                if (box->isHorizontal()) {
372                    r.setHeight(selectionRect.height().toFloat());
373                    r.setY(selectionRect.y().toFloat());
374                } else {
375                    r.setWidth(selectionRect.width().toFloat());
376                    r.setX(selectionRect.x().toFloat());
377                }
378            }
379            rects.append(localToAbsoluteQuad(r, 0, wasFixed).enclosingBoundingBox());
380        } else {
381            // FIXME: This code is wrong. It's converting local to absolute twice. http://webkit.org/b/65722
382            FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
383            if (!rect.isZero())
384                rects.append(localToAbsoluteQuad(rect, 0, wasFixed).enclosingBoundingBox());
385        }
386    }
387}
388
389static IntRect ellipsisRectForBox(InlineTextBox* box, unsigned startPos, unsigned endPos)
390{
391    if (!box)
392        return IntRect();
393
394    unsigned short truncation = box->truncation();
395    if (truncation == cNoTruncation)
396        return IntRect();
397
398    IntRect rect;
399    if (EllipsisBox* ellipsis = box->root().ellipsisBox()) {
400        int ellipsisStartPosition = std::max<int>(startPos - box->start(), 0);
401        int ellipsisEndPosition = std::min<int>(endPos - box->start(), box->len());
402
403        // The ellipsis should be considered to be selected if the end of
404        // the selection is past the beginning of the truncation and the
405        // beginning of the selection is before or at the beginning of the truncation.
406        if (ellipsisEndPosition >= truncation && ellipsisStartPosition <= truncation)
407            return ellipsis->selectionRect();
408    }
409
410    return IntRect();
411}
412
413void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed, ClippingOption option) const
414{
415    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
416        FloatRect boundaries = box->calculateBoundaries();
417
418        // Shorten the width of this text box if it ends in an ellipsis.
419        // FIXME: ellipsisRectForBox should switch to return FloatRect soon with the subpixellayout branch.
420        IntRect ellipsisRect = (option == ClipToEllipsis) ? ellipsisRectForBox(box, 0, textLength()) : IntRect();
421        if (!ellipsisRect.isEmpty()) {
422            if (style()->isHorizontalWritingMode())
423                boundaries.setWidth(ellipsisRect.maxX() - boundaries.x());
424            else
425                boundaries.setHeight(ellipsisRect.maxY() - boundaries.y());
426        }
427        quads.append(localToAbsoluteQuad(boundaries, 0, wasFixed));
428    }
429}
430
431void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
432{
433    absoluteQuads(quads, wasFixed, NoClipping);
434}
435
436void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
437{
438    // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
439    // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
440    // function to take ints causes various internal mismatches. But selectionRect takes ints, and
441    // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
442    // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
443    ASSERT(end == UINT_MAX || end <= INT_MAX);
444    ASSERT(start <= INT_MAX);
445    start = std::min(start, static_cast<unsigned>(INT_MAX));
446    end = std::min(end, static_cast<unsigned>(INT_MAX));
447
448    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
449        // Note: box->end() returns the index of the last character, not the index past it
450        if (start <= box->start() && box->end() < end) {
451            FloatRect r = box->calculateBoundaries();
452            if (useSelectionHeight) {
453                LayoutRect selectionRect = box->localSelectionRect(start, end);
454                if (box->isHorizontal()) {
455                    r.setHeight(selectionRect.height().toFloat());
456                    r.setY(selectionRect.y().toFloat());
457                } else {
458                    r.setWidth(selectionRect.width().toFloat());
459                    r.setX(selectionRect.x().toFloat());
460                }
461            }
462            quads.append(localToAbsoluteQuad(r, 0, wasFixed));
463        } else {
464            FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
465            if (!rect.isZero())
466                quads.append(localToAbsoluteQuad(rect, 0, wasFixed));
467        }
468    }
469}
470
471enum ShouldAffinityBeDownstream { AlwaysDownstream, AlwaysUpstream, UpstreamIfPositionIsNotAtStart };
472
473static bool lineDirectionPointFitsInBox(int pointLineDirection, InlineTextBox* box, ShouldAffinityBeDownstream& shouldAffinityBeDownstream)
474{
475    shouldAffinityBeDownstream = AlwaysDownstream;
476
477    // the x coordinate is equal to the left edge of this box
478    // the affinity must be downstream so the position doesn't jump back to the previous line
479    // except when box is the first box in the line
480    if (pointLineDirection <= box->logicalLeft()) {
481        shouldAffinityBeDownstream = !box->prevLeafChild() ? UpstreamIfPositionIsNotAtStart : AlwaysDownstream;
482        return true;
483    }
484
485    // and the x coordinate is to the left of the right edge of this box
486    // check to see if position goes in this box
487    if (pointLineDirection < box->logicalRight()) {
488        shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
489        return true;
490    }
491
492    // box is first on line
493    // and the x coordinate is to the left of the first text box left edge
494    if (!box->prevLeafChildIgnoringLineBreak() && pointLineDirection < box->logicalLeft())
495        return true;
496
497    if (!box->nextLeafChildIgnoringLineBreak()) {
498        // box is last on line
499        // and the x coordinate is to the right of the last text box right edge
500        // generate VisiblePosition, use UPSTREAM affinity if possible
501        shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
502        return true;
503    }
504
505    return false;
506}
507
508static PositionWithAffinity createPositionWithAffinityForBox(const InlineBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
509{
510    EAffinity affinity = VP_DEFAULT_AFFINITY;
511    switch (shouldAffinityBeDownstream) {
512    case AlwaysDownstream:
513        affinity = DOWNSTREAM;
514        break;
515    case AlwaysUpstream:
516        affinity = VP_UPSTREAM_IF_POSSIBLE;
517        break;
518    case UpstreamIfPositionIsNotAtStart:
519        affinity = offset > box->caretMinOffset() ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM;
520        break;
521    }
522    int textStartOffset = box->renderer().isText() ? toRenderText(box->renderer()).textStartOffset() : 0;
523    return box->renderer().createPositionWithAffinity(offset + textStartOffset, affinity);
524}
525
526static PositionWithAffinity createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(const InlineTextBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
527{
528    ASSERT(box);
529    ASSERT(offset >= 0);
530
531    if (offset && static_cast<unsigned>(offset) < box->len())
532        return createPositionWithAffinityForBox(box, box->start() + offset, shouldAffinityBeDownstream);
533
534    bool positionIsAtStartOfBox = !offset;
535    if (positionIsAtStartOfBox == box->isLeftToRightDirection()) {
536        // offset is on the left edge
537
538        const InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak();
539        if ((prevBox && prevBox->bidiLevel() == box->bidiLevel())
540            || box->renderer().containingBlock()->style()->direction() == box->direction()) // FIXME: left on 12CBA
541            return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
542
543        if (prevBox && prevBox->bidiLevel() > box->bidiLevel()) {
544            // e.g. left of B in aDC12BAb
545            const InlineBox* leftmostBox;
546            do {
547                leftmostBox = prevBox;
548                prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
549            } while (prevBox && prevBox->bidiLevel() > box->bidiLevel());
550            return createPositionWithAffinityForBox(leftmostBox, leftmostBox->caretRightmostOffset(), shouldAffinityBeDownstream);
551        }
552
553        if (!prevBox || prevBox->bidiLevel() < box->bidiLevel()) {
554            // e.g. left of D in aDC12BAb
555            const InlineBox* rightmostBox;
556            const InlineBox* nextBox = box;
557            do {
558                rightmostBox = nextBox;
559                nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
560            } while (nextBox && nextBox->bidiLevel() >= box->bidiLevel());
561            return createPositionWithAffinityForBox(rightmostBox,
562                box->isLeftToRightDirection() ? rightmostBox->caretMaxOffset() : rightmostBox->caretMinOffset(), shouldAffinityBeDownstream);
563        }
564
565        return createPositionWithAffinityForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
566    }
567
568    const InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak();
569    if ((nextBox && nextBox->bidiLevel() == box->bidiLevel())
570        || box->renderer().containingBlock()->style()->direction() == box->direction())
571        return createPositionWithAffinityForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
572
573    // offset is on the right edge
574    if (nextBox && nextBox->bidiLevel() > box->bidiLevel()) {
575        // e.g. right of C in aDC12BAb
576        const InlineBox* rightmostBox;
577        do {
578            rightmostBox = nextBox;
579            nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
580        } while (nextBox && nextBox->bidiLevel() > box->bidiLevel());
581        return createPositionWithAffinityForBox(rightmostBox, rightmostBox->caretLeftmostOffset(), shouldAffinityBeDownstream);
582    }
583
584    if (!nextBox || nextBox->bidiLevel() < box->bidiLevel()) {
585        // e.g. right of A in aDC12BAb
586        const InlineBox* leftmostBox;
587        const InlineBox* prevBox = box;
588        do {
589            leftmostBox = prevBox;
590            prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
591        } while (prevBox && prevBox->bidiLevel() >= box->bidiLevel());
592        return createPositionWithAffinityForBox(leftmostBox,
593            box->isLeftToRightDirection() ? leftmostBox->caretMinOffset() : leftmostBox->caretMaxOffset(), shouldAffinityBeDownstream);
594    }
595
596    return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
597}
598
599PositionWithAffinity RenderText::positionForPoint(const LayoutPoint& point)
600{
601    if (!firstTextBox() || textLength() == 0)
602        return createPositionWithAffinity(0, DOWNSTREAM);
603
604    LayoutUnit pointLineDirection = firstTextBox()->isHorizontal() ? point.x() : point.y();
605    LayoutUnit pointBlockDirection = firstTextBox()->isHorizontal() ? point.y() : point.x();
606    bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
607
608    InlineTextBox* lastBox = 0;
609    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
610        if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild() && !box->nextLeafChild()->isLineBreak())
611            box = box->nextTextBox();
612
613        RootInlineBox& rootBox = box->root();
614        LayoutUnit top = std::min(rootBox.selectionTop(), rootBox.lineTop());
615        if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirection == top)) {
616            LayoutUnit bottom = rootBox.selectionBottom();
617            if (rootBox.nextRootBox())
618                bottom = std::min(bottom, rootBox.nextRootBox()->lineTop());
619
620            if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockDirection == bottom)) {
621                ShouldAffinityBeDownstream shouldAffinityBeDownstream;
622                if (lineDirectionPointFitsInBox(pointLineDirection, box, shouldAffinityBeDownstream))
623                    return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(box, box->offsetForPosition(pointLineDirection.toFloat()), shouldAffinityBeDownstream);
624            }
625        }
626        lastBox = box;
627    }
628
629    if (lastBox) {
630        ShouldAffinityBeDownstream shouldAffinityBeDownstream;
631        lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityBeDownstream);
632        return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastBox, lastBox->offsetForPosition(pointLineDirection.toFloat()) + lastBox->start(), shouldAffinityBeDownstream);
633    }
634    return createPositionWithAffinity(0, DOWNSTREAM);
635}
636
637LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
638{
639    if (!inlineBox)
640        return LayoutRect();
641
642    ASSERT(inlineBox->isInlineTextBox());
643    if (!inlineBox->isInlineTextBox())
644        return LayoutRect();
645
646    InlineTextBox* box = toInlineTextBox(inlineBox);
647
648    int height = box->root().selectionHeight();
649    int top = box->root().selectionTop();
650
651    // Go ahead and round left to snap it to the nearest pixel.
652    float left = box->positionForOffset(caretOffset);
653
654    // Distribute the caret's width to either side of the offset.
655    int caretWidthLeftOfOffset = caretWidth / 2;
656    left -= caretWidthLeftOfOffset;
657    int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset;
658
659    left = roundf(left);
660
661    float rootLeft = box->root().logicalLeft();
662    float rootRight = box->root().logicalRight();
663
664    // FIXME: should we use the width of the root inline box or the
665    // width of the containing block for this?
666    if (extraWidthToEndOfLine)
667        *extraWidthToEndOfLine = (box->root().logicalWidth() + rootLeft) - (left + 1);
668
669    RenderBlock* cb = containingBlock();
670    RenderStyle* cbStyle = cb->style();
671
672    float leftEdge;
673    float rightEdge;
674    leftEdge = std::min<float>(0, rootLeft);
675    rightEdge = std::max<float>(cb->logicalWidth().toFloat(), rootRight);
676
677    bool rightAligned = false;
678    switch (cbStyle->textAlign()) {
679    case RIGHT:
680    case WEBKIT_RIGHT:
681        rightAligned = true;
682        break;
683    case LEFT:
684    case WEBKIT_LEFT:
685    case CENTER:
686    case WEBKIT_CENTER:
687        break;
688    case JUSTIFY:
689    case TASTART:
690        rightAligned = !cbStyle->isLeftToRightDirection();
691        break;
692    case TAEND:
693        rightAligned = cbStyle->isLeftToRightDirection();
694        break;
695    }
696
697    // for dir=auto, use inlineBoxBidiLevel() to test the correct direction for the cursor.
698    if (rightAligned && (node() && node()->selfOrAncestorHasDirAutoAttribute())) {
699        if (inlineBox->bidiLevel()%2 != 1)
700            rightAligned = false;
701    }
702
703    if (rightAligned) {
704        left = std::max(left, leftEdge);
705        left = std::min(left, rootRight - caretWidth);
706    } else {
707        left = std::min(left, rightEdge - caretWidthRightOfOffset);
708        left = std::max(left, rootLeft);
709    }
710
711    return style()->isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth);
712}
713
714ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
715{
716    if (style()->hasTextCombine() && isCombineText()) {
717        const RenderCombineText* combineText = toRenderCombineText(this);
718        if (combineText->isCombined())
719            return combineText->combinedTextWidth(f);
720    }
721
722    if (f.isFixedPitch() && f.fontDescription().variant() == FontVariantNormal && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
723        float monospaceCharacterWidth = f.spaceWidth();
724        float w = 0;
725        bool isSpace;
726        ASSERT(m_text);
727        StringImpl& text = *m_text.impl();
728        for (int i = start; i < start + len; i++) {
729            char c = text[i];
730            if (c <= space) {
731                if (c == space || c == newlineCharacter) {
732                    w += monospaceCharacterWidth;
733                    isSpace = true;
734                } else if (c == characterTabulation) {
735                    if (style()->collapseWhiteSpace()) {
736                        w += monospaceCharacterWidth;
737                        isSpace = true;
738                    } else {
739                        w += f.tabWidth(style()->tabSize(), xPos + w);
740                        isSpace = false;
741                    }
742                } else
743                    isSpace = false;
744            } else {
745                w += monospaceCharacterWidth;
746                isSpace = false;
747            }
748            if (isSpace && i > start)
749                w += f.fontDescription().wordSpacing();
750        }
751        return w;
752    }
753
754    TextRun run = constructTextRun(const_cast<RenderText*>(this), f, this, start, len, style(), textDirection);
755    run.setCharactersLength(textLength() - start);
756    ASSERT(run.charactersLength() >= run.length());
757
758    run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
759    run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
760    run.setXPos(xPos);
761    FontCachePurgePreventer fontCachePurgePreventer;
762    return f.width(run, fallbackFonts, glyphOverflow);
763}
764
765void RenderText::trimmedPrefWidths(float leadWidth,
766    float& firstLineMinWidth, bool& hasBreakableStart,
767    float& lastLineMinWidth, bool& hasBreakableEnd,
768    bool& hasBreakableChar, bool& hasBreak,
769    float& firstLineMaxWidth, float& lastLineMaxWidth,
770    float& minWidth, float& maxWidth, bool& stripFrontSpaces,
771    TextDirection direction)
772{
773    bool collapseWhiteSpace = style()->collapseWhiteSpace();
774    if (!collapseWhiteSpace)
775        stripFrontSpaces = false;
776
777    if (m_hasTab || preferredLogicalWidthsDirty())
778        computePreferredLogicalWidths(leadWidth);
779
780    hasBreakableStart = !stripFrontSpaces && m_hasBreakableStart;
781    hasBreakableEnd = m_hasBreakableEnd;
782
783    int len = textLength();
784
785    if (!len || (stripFrontSpaces && text().impl()->containsOnlyWhitespace())) {
786        firstLineMinWidth = 0;
787        lastLineMinWidth = 0;
788        firstLineMaxWidth = 0;
789        lastLineMaxWidth = 0;
790        minWidth = 0;
791        maxWidth = 0;
792        hasBreak = false;
793        return;
794    }
795
796    minWidth = m_minWidth;
797    maxWidth = m_maxWidth;
798
799    firstLineMinWidth = m_firstLineMinWidth;
800    lastLineMinWidth = m_lastLineLineMinWidth;
801
802    hasBreakableChar = m_hasBreakableChar;
803    hasBreak = m_hasBreak;
804
805    ASSERT(m_text);
806    StringImpl& text = *m_text.impl();
807    if (text[0] == space || (text[0] == newlineCharacter && !style()->preserveNewline()) || text[0] == characterTabulation) {
808        const Font& font = style()->font(); // FIXME: This ignores first-line.
809        if (stripFrontSpaces) {
810            const UChar spaceChar = space;
811            float spaceWidth = font.width(constructTextRun(this, font, &spaceChar, 1, style(), direction));
812            maxWidth -= spaceWidth;
813        } else {
814            maxWidth += font.fontDescription().wordSpacing();
815        }
816    }
817
818    stripFrontSpaces = collapseWhiteSpace && m_hasEndWhiteSpace;
819
820    if (!style()->autoWrap() || minWidth > maxWidth)
821        minWidth = maxWidth;
822
823    // Compute our max widths by scanning the string for newlines.
824    if (hasBreak) {
825        const Font& f = style()->font(); // FIXME: This ignores first-line.
826        bool firstLine = true;
827        firstLineMaxWidth = maxWidth;
828        lastLineMaxWidth = maxWidth;
829        for (int i = 0; i < len; i++) {
830            int linelen = 0;
831            while (i + linelen < len && text[i + linelen] != newlineCharacter)
832                linelen++;
833
834            if (linelen) {
835                lastLineMaxWidth = widthFromCache(f, i, linelen, leadWidth + lastLineMaxWidth, direction, 0, 0);
836                if (firstLine) {
837                    firstLine = false;
838                    leadWidth = 0;
839                    firstLineMaxWidth = lastLineMaxWidth;
840                }
841                i += linelen;
842            } else if (firstLine) {
843                firstLineMaxWidth = 0;
844                firstLine = false;
845                leadWidth = 0;
846            }
847
848            if (i == len - 1) {
849                // A <pre> run that ends with a newline, as in, e.g.,
850                // <pre>Some text\n\n<span>More text</pre>
851                lastLineMaxWidth = 0;
852            }
853        }
854    }
855}
856
857float RenderText::minLogicalWidth() const
858{
859    if (preferredLogicalWidthsDirty())
860        const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
861
862    return m_minWidth;
863}
864
865float RenderText::maxLogicalWidth() const
866{
867    if (preferredLogicalWidthsDirty())
868        const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
869
870    return m_maxWidth;
871}
872
873void RenderText::computePreferredLogicalWidths(float leadWidth)
874{
875    HashSet<const SimpleFontData*> fallbackFonts;
876    GlyphOverflow glyphOverflow;
877    computePreferredLogicalWidths(leadWidth, fallbackFonts, glyphOverflow);
878
879    // We shouldn't change our mind once we "know".
880    ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts || (fallbackFonts.isEmpty() && glyphOverflow.isZero()));
881    m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts.isEmpty() && glyphOverflow.isZero();
882}
883
884static inline float hyphenWidth(RenderText* renderer, const Font& font, TextDirection direction)
885{
886    RenderStyle* style = renderer->style();
887    return font.width(constructTextRun(renderer, font, style->hyphenString().string(), style, direction));
888}
889
890void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
891{
892    ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts);
893
894    m_minWidth = 0;
895    m_maxWidth = 0;
896    m_firstLineMinWidth = 0;
897    m_lastLineLineMinWidth = 0;
898
899    if (isBR())
900        return;
901
902    float currMinWidth = 0;
903    float currMaxWidth = 0;
904    m_hasBreakableChar = false;
905    m_hasBreak = false;
906    m_hasTab = false;
907    m_hasBreakableStart = false;
908    m_hasBreakableEnd = false;
909    m_hasEndWhiteSpace = false;
910
911    RenderStyle* styleToUse = style();
912    const Font& f = styleToUse->font(); // FIXME: This ignores first-line.
913    float wordSpacing = styleToUse->wordSpacing();
914    int len = textLength();
915    LazyLineBreakIterator breakIterator(m_text, styleToUse->locale());
916    bool needsWordSpacing = false;
917    bool ignoringSpaces = false;
918    bool isSpace = false;
919    bool firstWord = true;
920    bool firstLine = true;
921    int nextBreakable = -1;
922    int lastWordBoundary = 0;
923    float cachedWordTrailingSpaceWidth[2] = { 0, 0 }; // LTR, RTL
924
925    int firstGlyphLeftOverflow = -1;
926
927    bool breakAll = (styleToUse->wordBreak() == BreakAllWordBreak || styleToUse->wordBreak() == BreakWordBreak) && styleToUse->autoWrap();
928
929    TextRun textRun(text());
930    BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
931    BidiCharacterRun* run;
932    TextDirection textDirection = styleToUse->direction();
933    if (isOverride(styleToUse->unicodeBidi())) {
934        run = 0;
935    } else {
936        BidiStatus status(textDirection, false);
937        bidiResolver.setStatus(status);
938        bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&textRun, 0));
939        bool hardLineBreak = false;
940        bool reorderRuns = false;
941        bidiResolver.createBidiRunsForLine(TextRunIterator(&textRun, textRun.length()), NoVisualOverride, hardLineBreak, reorderRuns);
942        BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
943        run = bidiRuns.firstRun();
944    }
945
946    for (int i = 0; i < len; i++) {
947        UChar c = uncheckedCharacterAt(i);
948
949        if (run) {
950            // Treat adjacent runs with the same resolved directionality
951            // (TextDirection as opposed to WTF::Unicode::Direction) as belonging
952            // to the same run to avoid breaking unnecessarily.
953            while (i >= run->stop() || (run->next() && run->next()->direction() == run->direction()))
954                run = run->next();
955
956            ASSERT(run);
957            ASSERT(i <= run->stop());
958            textDirection = run->direction();
959        }
960
961        bool previousCharacterIsSpace = isSpace;
962        bool isNewline = false;
963        if (c == newlineCharacter) {
964            if (styleToUse->preserveNewline()) {
965                m_hasBreak = true;
966                isNewline = true;
967                isSpace = false;
968            } else
969                isSpace = true;
970        } else if (c == characterTabulation) {
971            if (!styleToUse->collapseWhiteSpace()) {
972                m_hasTab = true;
973                isSpace = false;
974            } else
975                isSpace = true;
976        } else {
977            isSpace = c == space;
978        }
979
980        bool isBreakableLocation = isNewline || (isSpace && styleToUse->autoWrap());
981        if (!i)
982            m_hasBreakableStart = isBreakableLocation;
983        if (i == len - 1) {
984            m_hasBreakableEnd = isBreakableLocation;
985            m_hasEndWhiteSpace = isNewline || isSpace;
986        }
987
988        if (!ignoringSpaces && styleToUse->collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
989            ignoringSpaces = true;
990
991        if (ignoringSpaces && !isSpace)
992            ignoringSpaces = false;
993
994        // Ignore spaces and soft hyphens
995        if (ignoringSpaces) {
996            ASSERT(lastWordBoundary == i);
997            lastWordBoundary++;
998            continue;
999        } else if (c == softHyphen) {
1000            currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
1001            if (firstGlyphLeftOverflow < 0)
1002                firstGlyphLeftOverflow = glyphOverflow.left;
1003            lastWordBoundary = i + 1;
1004            continue;
1005        }
1006
1007        bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable);
1008        bool betweenWords = true;
1009        int j = i;
1010        while (c != newlineCharacter && c != space && c != characterTabulation && (c != softHyphen)) {
1011            j++;
1012            if (j == len)
1013                break;
1014            c = uncheckedCharacterAt(j);
1015            if (isBreakable(breakIterator, j, nextBreakable) && characterAt(j - 1) != softHyphen)
1016                break;
1017            if (breakAll) {
1018                betweenWords = false;
1019                break;
1020            }
1021        }
1022
1023        // Terminate word boundary at bidi run boundary.
1024        if (run)
1025            j = std::min(j, run->stop() + 1);
1026        int wordLen = j - i;
1027        if (wordLen) {
1028            bool isSpace = (j < len) && c == space;
1029
1030            // Non-zero only when kerning is enabled, in which case we measure words with their trailing
1031            // space, then subtract its width.
1032            float wordTrailingSpaceWidth = 0;
1033            if (isSpace && (f.fontDescription().typesettingFeatures() & Kerning)) {
1034                ASSERT(textDirection >=0 && textDirection <= 1);
1035                if (!cachedWordTrailingSpaceWidth[textDirection])
1036                    cachedWordTrailingSpaceWidth[textDirection] = f.width(constructTextRun(this, f, &space, 1, styleToUse, textDirection)) + wordSpacing;
1037                wordTrailingSpaceWidth = cachedWordTrailingSpaceWidth[textDirection];
1038            }
1039
1040            float w;
1041            if (wordTrailingSpaceWidth && isSpace)
1042                w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth;
1043            else {
1044                w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
1045                if (c == softHyphen)
1046                    currMinWidth += hyphenWidth(this, f, textDirection);
1047            }
1048
1049            if (firstGlyphLeftOverflow < 0)
1050                firstGlyphLeftOverflow = glyphOverflow.left;
1051            currMinWidth += w;
1052            if (betweenWords) {
1053                if (lastWordBoundary == i)
1054                    currMaxWidth += w;
1055                else
1056                    currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
1057                lastWordBoundary = j;
1058            }
1059
1060            bool isCollapsibleWhiteSpace = (j < len) && styleToUse->isCollapsibleWhiteSpace(c);
1061            if (j < len && styleToUse->autoWrap())
1062                m_hasBreakableChar = true;
1063
1064            // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
1065            // last word in the run.
1066            if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
1067                currMaxWidth += wordSpacing;
1068
1069            if (firstWord) {
1070                firstWord = false;
1071                // If the first character in the run is breakable, then we consider ourselves to have a beginning
1072                // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
1073                // being appended to a previous text run when considering the total minimum width of the containing block.
1074                if (hasBreak)
1075                    m_hasBreakableChar = true;
1076                m_firstLineMinWidth = hasBreak ? 0 : currMinWidth;
1077            }
1078            m_lastLineLineMinWidth = currMinWidth;
1079
1080            if (currMinWidth > m_minWidth)
1081                m_minWidth = currMinWidth;
1082            currMinWidth = 0;
1083
1084            i += wordLen - 1;
1085        } else {
1086            // Nowrap can never be broken, so don't bother setting the
1087            // breakable character boolean. Pre can only be broken if we encounter a newline.
1088            if (style()->autoWrap() || isNewline)
1089                m_hasBreakableChar = true;
1090
1091            if (currMinWidth > m_minWidth)
1092                m_minWidth = currMinWidth;
1093            currMinWidth = 0;
1094
1095            if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
1096                if (firstLine) {
1097                    firstLine = false;
1098                    leadWidth = 0;
1099                    if (!styleToUse->autoWrap())
1100                        m_firstLineMinWidth = currMaxWidth;
1101                }
1102
1103                if (currMaxWidth > m_maxWidth)
1104                    m_maxWidth = currMaxWidth;
1105                currMaxWidth = 0;
1106            } else {
1107                TextRun run = constructTextRun(this, f, this, i, 1, styleToUse, textDirection);
1108                run.setCharactersLength(len - i);
1109                run.setUseComplexCodePath(!canUseSimpleFontCodePath());
1110                ASSERT(run.charactersLength() >= run.length());
1111                run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
1112                run.setXPos(leadWidth + currMaxWidth);
1113
1114                currMaxWidth += f.width(run);
1115                glyphOverflow.right = 0;
1116                needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
1117            }
1118            ASSERT(lastWordBoundary == i);
1119            lastWordBoundary++;
1120        }
1121    }
1122    if (run)
1123        bidiResolver.runs().deleteRuns();
1124
1125    if (firstGlyphLeftOverflow > 0)
1126        glyphOverflow.left = firstGlyphLeftOverflow;
1127
1128    if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord))
1129        currMaxWidth += wordSpacing;
1130
1131    m_minWidth = std::max(currMinWidth, m_minWidth);
1132    m_maxWidth = std::max(currMaxWidth, m_maxWidth);
1133
1134    if (!styleToUse->autoWrap())
1135        m_minWidth = m_maxWidth;
1136
1137    if (styleToUse->whiteSpace() == PRE) {
1138        if (firstLine)
1139            m_firstLineMinWidth = m_maxWidth;
1140        m_lastLineLineMinWidth = currMaxWidth;
1141    }
1142
1143    clearPreferredLogicalWidthsDirty();
1144}
1145
1146bool RenderText::isAllCollapsibleWhitespace() const
1147{
1148    unsigned length = textLength();
1149    if (is8Bit()) {
1150        for (unsigned i = 0; i < length; ++i) {
1151            if (!style()->isCollapsibleWhiteSpace(characters8()[i]))
1152                return false;
1153        }
1154        return true;
1155    }
1156    for (unsigned i = 0; i < length; ++i) {
1157        if (!style()->isCollapsibleWhiteSpace(characters16()[i]))
1158            return false;
1159    }
1160    return true;
1161}
1162
1163bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
1164{
1165    ASSERT(m_text);
1166    StringImpl& text = *m_text.impl();
1167    unsigned currPos;
1168    for (currPos = from;
1169    currPos < from + len && (text[currPos] == newlineCharacter || text[currPos] == space || text[currPos] == characterTabulation);
1170    currPos++) { }
1171    return currPos >= (from + len);
1172}
1173
1174FloatPoint RenderText::firstRunOrigin() const
1175{
1176    return IntPoint(firstRunX(), firstRunY());
1177}
1178
1179float RenderText::firstRunX() const
1180{
1181    return m_firstTextBox ? m_firstTextBox->x() : 0;
1182}
1183
1184float RenderText::firstRunY() const
1185{
1186    return m_firstTextBox ? m_firstTextBox->y() : 0;
1187}
1188
1189void RenderText::setSelectionState(SelectionState state)
1190{
1191    RenderObject::setSelectionState(state);
1192
1193    if (canUpdateSelectionOnRootLineBoxes()) {
1194        if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) {
1195            int startPos, endPos;
1196            selectionStartEnd(startPos, endPos);
1197            if (selectionState() == SelectionStart) {
1198                endPos = textLength();
1199
1200                // to handle selection from end of text to end of line
1201                if (startPos && startPos == endPos)
1202                    startPos = endPos - 1;
1203            } else if (selectionState() == SelectionEnd)
1204                startPos = 0;
1205
1206            for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1207                if (box->isSelected(startPos, endPos)) {
1208                    box->root().setHasSelectedChildren(true);
1209                }
1210            }
1211        } else {
1212            for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1213                box->root().setHasSelectedChildren(state == SelectionInside);
1214            }
1215        }
1216    }
1217
1218    // The containing block can be null in case of an orphaned tree.
1219    RenderBlock* containingBlock = this->containingBlock();
1220    if (containingBlock && !containingBlock->isRenderView())
1221        containingBlock->setSelectionState(state);
1222}
1223
1224void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force)
1225{
1226    if (!force && equal(m_text.impl(), text.get()))
1227        return;
1228
1229    unsigned oldLen = textLength();
1230    unsigned newLen = text->length();
1231    int delta = newLen - oldLen;
1232    unsigned end = len ? offset + len - 1 : offset;
1233
1234    RootInlineBox* firstRootBox = 0;
1235    RootInlineBox* lastRootBox = 0;
1236
1237    bool dirtiedLines = false;
1238
1239    // Dirty all text boxes that include characters in between offset and offset+len.
1240    for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1241        // FIXME: This shouldn't rely on the end of a dirty line box. See https://bugs.webkit.org/show_bug.cgi?id=97264
1242        // Text run is entirely before the affected range.
1243        if (curr->end() < offset)
1244            continue;
1245
1246        // Text run is entirely after the affected range.
1247        if (curr->start() > end) {
1248            curr->offsetRun(delta);
1249            RootInlineBox* root = &curr->root();
1250            if (!firstRootBox) {
1251                firstRootBox = root;
1252                // The affected area was in between two runs. Go ahead and mark the root box of
1253                // the run after the affected area as dirty.
1254                firstRootBox->markDirty();
1255                dirtiedLines = true;
1256            }
1257            lastRootBox = root;
1258        } else if (curr->end() >= offset && curr->end() <= end) {
1259            // Text run overlaps with the left end of the affected range.
1260            curr->dirtyLineBoxes();
1261            dirtiedLines = true;
1262        } else if (curr->start() <= offset && curr->end() >= end) {
1263            // Text run subsumes the affected range.
1264            curr->dirtyLineBoxes();
1265            dirtiedLines = true;
1266        } else if (curr->start() <= end && curr->end() >= end) {
1267            // Text run overlaps with right end of the affected range.
1268            curr->dirtyLineBoxes();
1269            dirtiedLines = true;
1270        }
1271    }
1272
1273    // Now we have to walk all of the clean lines and adjust their cached line break information
1274    // to reflect our updated offsets.
1275    if (lastRootBox)
1276        lastRootBox = lastRootBox->nextRootBox();
1277    if (firstRootBox) {
1278        RootInlineBox* prev = firstRootBox->prevRootBox();
1279        if (prev)
1280            firstRootBox = prev;
1281    } else if (lastTextBox()) {
1282        ASSERT(!lastRootBox);
1283        firstRootBox = &lastTextBox()->root();
1284        firstRootBox->markDirty();
1285        dirtiedLines = true;
1286    }
1287    for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
1288        if (curr->lineBreakObj() == this && curr->lineBreakPos() > end)
1289            curr->setLineBreakPos(clampToInteger(curr->lineBreakPos() + delta));
1290    }
1291
1292    // If the text node is empty, dirty the line where new text will be inserted.
1293    if (!firstTextBox() && parent()) {
1294        parent()->dirtyLinesFromChangedChild(this);
1295        dirtiedLines = true;
1296    }
1297
1298    m_linesDirty = dirtiedLines;
1299    setText(text, force || dirtiedLines);
1300}
1301
1302void RenderText::transformText()
1303{
1304    if (RefPtr<StringImpl> textToTransform = originalText())
1305        setText(textToTransform.release(), true);
1306}
1307
1308static inline bool isInlineFlowOrEmptyText(const RenderObject* o)
1309{
1310    if (o->isRenderInline())
1311        return true;
1312    if (!o->isText())
1313        return false;
1314    return toRenderText(o)->text().isEmpty();
1315}
1316
1317UChar RenderText::previousCharacter() const
1318{
1319    // find previous text renderer if one exists
1320    const RenderObject* previousText = previousInPreOrder();
1321    for (; previousText; previousText = previousText->previousInPreOrder())
1322        if (!isInlineFlowOrEmptyText(previousText))
1323            break;
1324    UChar prev = space;
1325    if (previousText && previousText->isText())
1326        if (StringImpl* previousString = toRenderText(previousText)->text().impl())
1327            prev = (*previousString)[previousString->length() - 1];
1328    return prev;
1329}
1330
1331void RenderText::addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
1332{
1333    // Text nodes aren't event targets, so don't descend any further.
1334}
1335
1336void applyTextTransform(const RenderStyle* style, String& text, UChar previousCharacter)
1337{
1338    if (!style)
1339        return;
1340
1341    switch (style->textTransform()) {
1342    case TTNONE:
1343        break;
1344    case CAPITALIZE:
1345        makeCapitalized(&text, previousCharacter);
1346        break;
1347    case UPPERCASE:
1348        text = text.upper(style->locale());
1349        break;
1350    case LOWERCASE:
1351        text = text.lower(style->locale());
1352        break;
1353    }
1354}
1355
1356void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
1357{
1358    ASSERT(text);
1359    m_text = text;
1360
1361    if (style()) {
1362        applyTextTransform(style(), m_text, previousCharacter());
1363
1364        // We use the same characters here as for list markers.
1365        // See the listMarkerText function in RenderListMarker.cpp.
1366        switch (style()->textSecurity()) {
1367        case TSNONE:
1368            break;
1369        case TSCIRCLE:
1370            secureText(whiteBullet);
1371            break;
1372        case TSDISC:
1373            secureText(bullet);
1374            break;
1375        case TSSQUARE:
1376            secureText(blackSquare);
1377        }
1378    }
1379
1380    ASSERT(m_text);
1381    ASSERT(!isBR() || (textLength() == 1 && m_text[0] == newlineCharacter));
1382
1383    m_isAllASCII = m_text.containsOnlyASCII();
1384    m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
1385}
1386
1387void RenderText::secureText(UChar mask)
1388{
1389    if (!m_text.length())
1390        return;
1391
1392    int lastTypedCharacterOffsetToReveal = -1;
1393    UChar revealedText;
1394    SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->get(this) : 0;
1395    if (secureTextTimer && secureTextTimer->isActive()) {
1396        lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOffset();
1397        if (lastTypedCharacterOffsetToReveal >= 0)
1398            revealedText = m_text[lastTypedCharacterOffsetToReveal];
1399    }
1400
1401    m_text.fill(mask);
1402    if (lastTypedCharacterOffsetToReveal >= 0) {
1403        m_text.replace(lastTypedCharacterOffsetToReveal, 1, String(&revealedText, 1));
1404        // m_text may be updated later before timer fires. We invalidate the lastTypedCharacterOffset to avoid inconsistency.
1405        secureTextTimer->invalidate();
1406    }
1407}
1408
1409void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
1410{
1411    ASSERT(text);
1412
1413    if (!force && equal(m_text.impl(), text.get()))
1414        return;
1415
1416    setTextInternal(text);
1417    // If preferredLogicalWidthsDirty() of an orphan child is true, RenderObjectChildList::
1418    // insertChildNode() fails to set true to owner. To avoid that, we call
1419    // setNeedsLayoutAndPrefWidthsRecalc() only if this RenderText has parent.
1420    if (parent())
1421        setNeedsLayoutAndPrefWidthsRecalc();
1422    m_knownToHaveNoOverflowAndNoFallbackFonts = false;
1423
1424    if (AXObjectCache* cache = document().existingAXObjectCache())
1425        cache->textChanged(this);
1426}
1427
1428void RenderText::dirtyLineBoxes(bool fullLayout)
1429{
1430    if (fullLayout)
1431        deleteTextBoxes();
1432    else if (!m_linesDirty) {
1433        for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1434            box->dirtyLineBoxes();
1435    }
1436    m_linesDirty = false;
1437}
1438
1439InlineTextBox* RenderText::createTextBox()
1440{
1441    return new InlineTextBox(*this);
1442}
1443
1444InlineTextBox* RenderText::createInlineTextBox()
1445{
1446    InlineTextBox* textBox = createTextBox();
1447    if (!m_firstTextBox)
1448        m_firstTextBox = m_lastTextBox = textBox;
1449    else {
1450        m_lastTextBox->setNextTextBox(textBox);
1451        textBox->setPreviousTextBox(m_lastTextBox);
1452        m_lastTextBox = textBox;
1453    }
1454    textBox->setIsText(true);
1455    return textBox;
1456}
1457
1458void RenderText::positionLineBox(InlineBox* box)
1459{
1460    InlineTextBox* s = toInlineTextBox(box);
1461
1462    // FIXME: should not be needed!!!
1463    if (!s->len()) {
1464        // We want the box to be destroyed.
1465        s->remove(DontMarkLineBoxes);
1466        if (m_firstTextBox == s)
1467            m_firstTextBox = s->nextTextBox();
1468        else
1469            s->prevTextBox()->setNextTextBox(s->nextTextBox());
1470        if (m_lastTextBox == s)
1471            m_lastTextBox = s->prevTextBox();
1472        else
1473            s->nextTextBox()->setPreviousTextBox(s->prevTextBox());
1474        s->destroy();
1475        return;
1476    }
1477
1478    m_containsReversedText |= !s->isLeftToRightDirection();
1479}
1480
1481float RenderText::width(unsigned from, unsigned len, float xPos, TextDirection textDirection, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1482{
1483    if (from >= textLength())
1484        return 0;
1485
1486    if (from + len > textLength())
1487        len = textLength() - from;
1488
1489    return width(from, len, style(firstLine)->font(), xPos, textDirection, fallbackFonts, glyphOverflow);
1490}
1491
1492float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1493{
1494    ASSERT(from + len <= textLength());
1495    if (!textLength())
1496        return 0;
1497
1498    float w;
1499    if (&f == &style()->font()) {
1500        if (!style()->preserveNewline() && !from && len == textLength() && (!glyphOverflow || !glyphOverflow->computeBounds)) {
1501            if (fallbackFonts) {
1502                ASSERT(glyphOverflow);
1503                if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
1504                    const_cast<RenderText*>(this)->computePreferredLogicalWidths(0, *fallbackFonts, *glyphOverflow);
1505                    // We shouldn't change our mind once we "know".
1506                    ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts
1507                        || (fallbackFonts->isEmpty() && glyphOverflow->isZero()));
1508                    m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts->isEmpty() && glyphOverflow->isZero();
1509                }
1510                w = m_maxWidth;
1511            } else {
1512                w = maxLogicalWidth();
1513            }
1514        } else {
1515            w = widthFromCache(f, from, len, xPos, textDirection, fallbackFonts, glyphOverflow);
1516        }
1517    } else {
1518        TextRun run = constructTextRun(const_cast<RenderText*>(this), f, this, from, len, style(), textDirection);
1519        run.setCharactersLength(textLength() - from);
1520        ASSERT(run.charactersLength() >= run.length());
1521
1522        run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
1523        run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
1524        run.setXPos(xPos);
1525        w = f.width(run, fallbackFonts, glyphOverflow);
1526    }
1527
1528    return w;
1529}
1530
1531IntRect RenderText::linesBoundingBox() const
1532{
1533    IntRect result;
1534
1535    ASSERT(!firstTextBox() == !lastTextBox());  // Either both are null or both exist.
1536    if (firstTextBox() && lastTextBox()) {
1537        // Return the width of the minimal left side and the maximal right side.
1538        float logicalLeftSide = 0;
1539        float logicalRightSide = 0;
1540        for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1541            if (curr == firstTextBox() || curr->logicalLeft() < logicalLeftSide)
1542                logicalLeftSide = curr->logicalLeft();
1543            if (curr == firstTextBox() || curr->logicalRight() > logicalRightSide)
1544                logicalRightSide = curr->logicalRight();
1545        }
1546
1547        bool isHorizontal = style()->isHorizontalWritingMode();
1548
1549        float x = isHorizontal ? logicalLeftSide : firstTextBox()->x();
1550        float y = isHorizontal ? firstTextBox()->y() : logicalLeftSide;
1551        float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTextBox()->logicalBottom() - x;
1552        float height = isHorizontal ? lastTextBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
1553        result = enclosingIntRect(FloatRect(x, y, width, height));
1554    }
1555
1556    return result;
1557}
1558
1559LayoutRect RenderText::linesVisualOverflowBoundingBox() const
1560{
1561    if (!firstTextBox())
1562        return LayoutRect();
1563
1564    // Return the width of the minimal left side and the maximal right side.
1565    LayoutUnit logicalLeftSide = LayoutUnit::max();
1566    LayoutUnit logicalRightSide = LayoutUnit::min();
1567    for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1568        LayoutRect logicalVisualOverflow = curr->logicalOverflowRect();
1569        logicalLeftSide = std::min(logicalLeftSide, logicalVisualOverflow.x());
1570        logicalRightSide = std::max(logicalRightSide, logicalVisualOverflow.maxX());
1571    }
1572
1573    LayoutUnit logicalTop = firstTextBox()->logicalTopVisualOverflow();
1574    LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
1575    LayoutUnit logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - logicalTop;
1576
1577    LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
1578    if (!style()->isHorizontalWritingMode())
1579        rect = rect.transposedRect();
1580    return rect;
1581}
1582
1583LayoutRect RenderText::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
1584{
1585    // This method doesn't support paintInvalidationState, but invalidateTreeIfNeeded() never reaches RenderText.
1586    ASSERT(!paintInvalidationState);
1587    return parent()->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer);
1588}
1589
1590LayoutRect RenderText::selectionRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const
1591{
1592    ASSERT(!needsLayout());
1593
1594    if (selectionState() == SelectionNone)
1595        return LayoutRect();
1596    RenderBlock* cb = containingBlock();
1597    if (!cb)
1598        return LayoutRect();
1599
1600    // Now calculate startPos and endPos for painting selection.
1601    // We include a selection while endPos > 0
1602    int startPos, endPos;
1603    if (selectionState() == SelectionInside) {
1604        // We are fully selected.
1605        startPos = 0;
1606        endPos = textLength();
1607    } else {
1608        selectionStartEnd(startPos, endPos);
1609        if (selectionState() == SelectionStart)
1610            endPos = textLength();
1611        else if (selectionState() == SelectionEnd)
1612            startPos = 0;
1613    }
1614
1615    if (startPos == endPos)
1616        return IntRect();
1617
1618    LayoutRect rect;
1619    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1620        rect.unite(box->localSelectionRect(startPos, endPos));
1621        rect.unite(ellipsisRectForBox(box, startPos, endPos));
1622    }
1623
1624    mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, 0);
1625    return rect;
1626}
1627
1628int RenderText::caretMinOffset() const
1629{
1630    InlineTextBox* box = firstTextBox();
1631    if (!box)
1632        return 0;
1633    int minOffset = box->start();
1634    for (box = box->nextTextBox(); box; box = box->nextTextBox())
1635        minOffset = std::min<int>(minOffset, box->start());
1636    return minOffset;
1637}
1638
1639int RenderText::caretMaxOffset() const
1640{
1641    InlineTextBox* box = lastTextBox();
1642    if (!lastTextBox())
1643        return textLength();
1644
1645    int maxOffset = box->start() + box->len();
1646    for (box = box->prevTextBox(); box; box = box->prevTextBox())
1647        maxOffset = std::max<int>(maxOffset, box->start() + box->len());
1648    return maxOffset;
1649}
1650
1651unsigned RenderText::renderedTextLength() const
1652{
1653    int l = 0;
1654    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1655        l += box->len();
1656    return l;
1657}
1658
1659int RenderText::previousOffset(int current) const
1660{
1661    if (isAllASCII() || m_text.is8Bit())
1662        return current - 1;
1663
1664    StringImpl* textImpl = m_text.impl();
1665    TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
1666    if (!iterator)
1667        return current - 1;
1668
1669    long result = iterator->preceding(current);
1670    if (result == TextBreakDone)
1671        result = current - 1;
1672
1673
1674    return result;
1675}
1676
1677#if OS(POSIX)
1678
1679#define HANGUL_CHOSEONG_START (0x1100)
1680#define HANGUL_CHOSEONG_END (0x115F)
1681#define HANGUL_JUNGSEONG_START (0x1160)
1682#define HANGUL_JUNGSEONG_END (0x11A2)
1683#define HANGUL_JONGSEONG_START (0x11A8)
1684#define HANGUL_JONGSEONG_END (0x11F9)
1685#define HANGUL_SYLLABLE_START (0xAC00)
1686#define HANGUL_SYLLABLE_END (0xD7AF)
1687#define HANGUL_JONGSEONG_COUNT (28)
1688
1689enum HangulState {
1690    HangulStateL,
1691    HangulStateV,
1692    HangulStateT,
1693    HangulStateLV,
1694    HangulStateLVT,
1695    HangulStateBreak
1696};
1697
1698inline bool isHangulLVT(UChar32 character)
1699{
1700    return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
1701}
1702
1703inline bool isMark(UChar32 c)
1704{
1705    int8_t charType = u_charType(c);
1706    return charType == U_NON_SPACING_MARK || charType == U_ENCLOSING_MARK || charType == U_COMBINING_SPACING_MARK;
1707}
1708
1709inline bool isRegionalIndicator(UChar32 c)
1710{
1711    // National flag emoji each consists of a pair of regional indicator symbols.
1712    return 0x1F1E6 <= c && c <= 0x1F1FF;
1713}
1714
1715#endif
1716
1717int RenderText::previousOffsetForBackwardDeletion(int current) const
1718{
1719#if OS(POSIX)
1720    ASSERT(m_text);
1721    StringImpl& text = *m_text.impl();
1722    UChar32 character;
1723    bool sawRegionalIndicator = false;
1724    while (current > 0) {
1725        if (U16_IS_TRAIL(text[--current]))
1726            --current;
1727        if (current < 0)
1728            break;
1729
1730        UChar32 character = text.characterStartingAt(current);
1731
1732        if (sawRegionalIndicator) {
1733            // We don't check if the pair of regional indicator symbols before current position can actually be combined
1734            // into a flag, and just delete it. This may not agree with how the pair is rendered in edge cases,
1735            // but is good enough in practice.
1736            if (isRegionalIndicator(character))
1737                break;
1738            // Don't delete a preceding character that isn't a regional indicator symbol.
1739            U16_FWD_1_UNSAFE(text, current);
1740        }
1741
1742        // We don't combine characters in Armenian ... Limbu range for backward deletion.
1743        if ((character >= 0x0530) && (character < 0x1950))
1744            break;
1745
1746        if (isRegionalIndicator(character)) {
1747            sawRegionalIndicator = true;
1748            continue;
1749        }
1750
1751        if (!isMark(character) && (character != 0xFF9E) && (character != 0xFF9F))
1752            break;
1753    }
1754
1755    if (current <= 0)
1756        return current;
1757
1758    // Hangul
1759    character = text.characterStartingAt(current);
1760    if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) {
1761        HangulState state;
1762
1763        if (character < HANGUL_JUNGSEONG_START)
1764            state = HangulStateL;
1765        else if (character < HANGUL_JONGSEONG_START)
1766            state = HangulStateV;
1767        else if (character < HANGUL_SYLLABLE_START)
1768            state = HangulStateT;
1769        else
1770            state = isHangulLVT(character) ? HangulStateLVT : HangulStateLV;
1771
1772        while (current > 0 && ((character = text.characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) {
1773            switch (state) {
1774            case HangulStateV:
1775                if (character <= HANGUL_CHOSEONG_END)
1776                    state = HangulStateL;
1777                else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END) && !isHangulLVT(character))
1778                    state = HangulStateLV;
1779                else if (character > HANGUL_JUNGSEONG_END)
1780                    state = HangulStateBreak;
1781                break;
1782            case HangulStateT:
1783                if ((character >= HANGUL_JUNGSEONG_START) && (character <= HANGUL_JUNGSEONG_END))
1784                    state = HangulStateV;
1785                else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))
1786                    state = (isHangulLVT(character) ? HangulStateLVT : HangulStateLV);
1787                else if (character < HANGUL_JUNGSEONG_START)
1788                    state = HangulStateBreak;
1789                break;
1790            default:
1791                state = (character < HANGUL_JUNGSEONG_START) ? HangulStateL : HangulStateBreak;
1792                break;
1793            }
1794            if (state == HangulStateBreak)
1795                break;
1796
1797            --current;
1798        }
1799    }
1800
1801    return current;
1802#else
1803    // Platforms other than Unix-like delete by one code point.
1804    if (U16_IS_TRAIL(m_text[--current]))
1805        --current;
1806    if (current < 0)
1807        current = 0;
1808    return current;
1809#endif
1810}
1811
1812int RenderText::nextOffset(int current) const
1813{
1814    if (isAllASCII() || m_text.is8Bit())
1815        return current + 1;
1816
1817    StringImpl* textImpl = m_text.impl();
1818    TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
1819    if (!iterator)
1820        return current + 1;
1821
1822    long result = iterator->following(current);
1823    if (result == TextBreakDone)
1824        result = current + 1;
1825
1826    return result;
1827}
1828
1829bool RenderText::computeCanUseSimpleFontCodePath() const
1830{
1831    if (isAllASCII() || m_text.is8Bit())
1832        return true;
1833    return Character::characterRangeCodePath(characters16(), length()) == SimplePath;
1834}
1835
1836#if ENABLE(ASSERT)
1837
1838void RenderText::checkConsistency() const
1839{
1840#ifdef CHECK_CONSISTENCY
1841    const InlineTextBox* prev = 0;
1842    for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) {
1843        ASSERT(child->renderer() == this);
1844        ASSERT(child->prevTextBox() == prev);
1845        prev = child;
1846    }
1847    ASSERT(prev == m_lastTextBox);
1848#endif
1849}
1850
1851#endif
1852
1853void RenderText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset)
1854{
1855    if (!gSecureTextTimers)
1856        gSecureTextTimers = new SecureTextTimerMap;
1857
1858    SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this);
1859    if (!secureTextTimer) {
1860        secureTextTimer = new SecureTextTimer(this);
1861        gSecureTextTimers->add(this, secureTextTimer);
1862    }
1863    secureTextTimer->restartWithNewText(lastTypedCharacterOffset);
1864}
1865
1866PassRefPtr<AbstractInlineTextBox> RenderText::firstAbstractInlineTextBox()
1867{
1868    return AbstractInlineTextBox::getOrCreate(this, m_firstTextBox);
1869}
1870
1871} // namespace blink
1872