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