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