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