Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / RenderText.cpp
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
53 using namespace WTF;
54 using namespace Unicode;
55
56 namespace blink {
57
58 struct SameSizeAsRenderText : public RenderObject {
59     uint32_t bitfields : 16;
60     float widths[4];
61     String text;
62     void* pointers[2];
63 };
64
65 COMPILE_ASSERT(sizeof(RenderText) == sizeof(SameSizeAsRenderText), RenderText_should_stay_small);
66
67 class SecureTextTimer;
68 typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap;
69 static SecureTextTimerMap* gSecureTextTimers = 0;
70
71 class SecureTextTimer FINAL : public TimerBase {
72 public:
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
88 private:
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
99 static 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
139 RenderText::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
168 RenderText::~RenderText()
169 {
170     ASSERT(!m_firstTextBox);
171     ASSERT(!m_lastTextBox);
172 }
173
174 #endif
175
176 const char* RenderText::renderName() const
177 {
178     return "RenderText";
179 }
180
181 bool RenderText::isTextFragment() const
182 {
183     return false;
184 }
185
186 bool RenderText::isWordBreak() const
187 {
188     return false;
189 }
190
191 void 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
215 void 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
232 void RenderText::willBeDestroyed()
233 {
234     if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->take(this) : 0)
235         delete secureTextTimer;
236
237     removeAndDestroyTextBoxes();
238     RenderObject::willBeDestroyed();
239 }
240
241 void 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
257 void 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
276 void 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
292 void 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
304 PassRefPtr<StringImpl> RenderText::originalText() const
305 {
306     Node* e = node();
307     return (e && e->isTextNode()) ? toText(e)->dataImpl() : 0;
308 }
309
310 String 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
326 void 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
332 static 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
353 void 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
389 static 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
413 void 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
431 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
432 {
433     absoluteQuads(quads, wasFixed, NoClipping);
434 }
435
436 void 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
471 enum ShouldAffinityBeDownstream { AlwaysDownstream, AlwaysUpstream, UpstreamIfPositionIsNotAtStart };
472
473 static 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
508 static 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
526 static 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
599 PositionWithAffinity 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
637 LayoutRect 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
714 ALWAYS_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
765 void 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
857 float RenderText::minLogicalWidth() const
858 {
859     if (preferredLogicalWidthsDirty())
860         const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
861
862     return m_minWidth;
863 }
864
865 float RenderText::maxLogicalWidth() const
866 {
867     if (preferredLogicalWidthsDirty())
868         const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
869
870     return m_maxWidth;
871 }
872
873 void 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
884 static 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
890 void 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
1146 bool 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
1163 bool 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
1174 FloatPoint RenderText::firstRunOrigin() const
1175 {
1176     return IntPoint(firstRunX(), firstRunY());
1177 }
1178
1179 float RenderText::firstRunX() const
1180 {
1181     return m_firstTextBox ? m_firstTextBox->x() : 0;
1182 }
1183
1184 float RenderText::firstRunY() const
1185 {
1186     return m_firstTextBox ? m_firstTextBox->y() : 0;
1187 }
1188
1189 void 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
1224 void 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
1302 void RenderText::transformText()
1303 {
1304     if (RefPtr<StringImpl> textToTransform = originalText())
1305         setText(textToTransform.release(), true);
1306 }
1307
1308 static 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
1317 UChar 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
1331 void 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
1336 void 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
1356 void 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
1387 void 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
1409 void 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
1428 void 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
1439 InlineTextBox* RenderText::createTextBox()
1440 {
1441     return new InlineTextBox(*this);
1442 }
1443
1444 InlineTextBox* 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
1458 void 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
1481 float 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
1492 float 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
1531 IntRect 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
1559 LayoutRect 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
1583 LayoutRect 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
1590 LayoutRect 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
1628 int 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
1639 int 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
1651 unsigned 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
1659 int 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
1689 enum HangulState {
1690     HangulStateL,
1691     HangulStateV,
1692     HangulStateT,
1693     HangulStateLV,
1694     HangulStateLVT,
1695     HangulStateBreak
1696 };
1697
1698 inline bool isHangulLVT(UChar32 character)
1699 {
1700     return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
1701 }
1702
1703 inline 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
1709 inline 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
1717 int 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
1812 int 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
1829 bool 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
1838 void 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
1853 void 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
1866 PassRefPtr<AbstractInlineTextBox> RenderText::firstAbstractInlineTextBox()
1867 {
1868     return AbstractInlineTextBox::getOrCreate(this, m_firstTextBox);
1869 }
1870
1871 } // namespace blink