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