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