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 "core/rendering/RenderText.h"
     27 
     28 #include "core/accessibility/AXObjectCache.h"
     29 #include "core/dom/Text.h"
     30 #include "core/editing/TextIterator.h"
     31 #include "core/frame/FrameView.h"
     32 #include "core/frame/Settings.h"
     33 #include "core/html/parser/TextResourceDecoder.h"
     34 #include "core/rendering/AbstractInlineTextBox.h"
     35 #include "core/rendering/EllipsisBox.h"
     36 #include "core/rendering/InlineTextBox.h"
     37 #include "core/rendering/RenderBlock.h"
     38 #include "core/rendering/RenderCombineText.h"
     39 #include "core/rendering/RenderLayer.h"
     40 #include "core/rendering/RenderView.h"
     41 #include "core/rendering/break_lines.h"
     42 #include "platform/fonts/Character.h"
     43 #include "platform/fonts/FontCache.h"
     44 #include "platform/geometry/FloatQuad.h"
     45 #include "platform/text/BidiResolver.h"
     46 #include "platform/text/TextBreakIterator.h"
     47 #include "platform/text/TextRunIterator.h"
     48 #include "wtf/text/StringBuffer.h"
     49 #include "wtf/text/StringBuilder.h"
     50 #include "wtf/unicode/CharacterNames.h"
     51 
     52 using namespace std;
     53 using namespace WTF;
     54 using namespace Unicode;
     55 
     56 namespace WebCore {
     57 
     58 struct SameSizeAsRenderText : public RenderObject {
     59     uint32_t bitfields : 16;
     60     float widths[4];
     61     String text;
     62     void* pointers[2];
     63 };
     64 
     65 COMPILE_ASSERT(sizeof(RenderText) == sizeof(SameSizeAsRenderText), RenderText_should_stay_small);
     66 
     67 class SecureTextTimer;
     68 typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap;
     69 static SecureTextTimerMap* gSecureTextTimers = 0;
     70 
     71 class SecureTextTimer FINAL : public TimerBase {
     72 public:
     73     SecureTextTimer(RenderText* renderText)
     74         : m_renderText(renderText)
     75         , m_lastTypedCharacterOffset(-1)
     76     {
     77     }
     78 
     79     void restartWithNewText(unsigned lastTypedCharacterOffset)
     80     {
     81         m_lastTypedCharacterOffset = lastTypedCharacterOffset;
     82         if (Settings* settings = m_renderText->document().settings())
     83             startOneShot(settings->passwordEchoDurationInSeconds(), FROM_HERE);
     84     }
     85     void invalidate() { m_lastTypedCharacterOffset = -1; }
     86     unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; }
     87 
     88 private:
     89     virtual void fired() OVERRIDE
     90     {
     91         ASSERT(gSecureTextTimers->contains(m_renderText));
     92         m_renderText->setText(m_renderText->text().impl(), true /* forcing setting text as it may be masked later */);
     93     }
     94 
     95     RenderText* m_renderText;
     96     int m_lastTypedCharacterOffset;
     97 };
     98 
     99 static void makeCapitalized(String* string, UChar previous)
    100 {
    101     if (string->isNull())
    102         return;
    103 
    104     unsigned length = string->length();
    105     const StringImpl& input = *string->impl();
    106 
    107     if (length >= numeric_limits<unsigned>::max())
    108         CRASH();
    109 
    110     StringBuffer<UChar> stringWithPrevious(length + 1);
    111     stringWithPrevious[0] = previous == noBreakSpace ? ' ' : previous;
    112     for (unsigned i = 1; i < length + 1; i++) {
    113         // Replace &nbsp with a real space since ICU no longer treats &nbsp as a word separator.
    114         if (input[i - 1] == noBreakSpace)
    115             stringWithPrevious[i] = ' ';
    116         else
    117             stringWithPrevious[i] = input[i - 1];
    118     }
    119 
    120     TextBreakIterator* boundary = wordBreakIterator(stringWithPrevious.characters(), length + 1);
    121     if (!boundary)
    122         return;
    123 
    124     StringBuilder result;
    125     result.reserveCapacity(length);
    126 
    127     int32_t endOfWord;
    128     int32_t startOfWord = boundary->first();
    129     for (endOfWord = boundary->next(); endOfWord != TextBreakDone; startOfWord = endOfWord, endOfWord = boundary->next()) {
    130         if (startOfWord) // Ignore first char of previous string
    131             result.append(input[startOfWord - 1] == noBreakSpace ? noBreakSpace : toTitleCase(stringWithPrevious[startOfWord]));
    132         for (int i = startOfWord + 1; i < endOfWord; i++)
    133             result.append(input[i - 1]);
    134     }
    135 
    136     *string = result.toString();
    137 }
    138 
    139 RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
    140     : RenderObject(!node || node->isDocumentNode() ? 0 : node)
    141     , m_hasTab(false)
    142     , m_linesDirty(false)
    143     , m_containsReversedText(false)
    144     , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
    145     , m_minWidth(-1)
    146     , m_maxWidth(-1)
    147     , m_firstLineMinWidth(0)
    148     , m_lastLineLineMinWidth(0)
    149     , m_text(str)
    150     , m_firstTextBox(0)
    151     , m_lastTextBox(0)
    152 {
    153     ASSERT(m_text);
    154     // FIXME: Some clients of RenderText (and subclasses) pass Document as node to create anonymous renderer.
    155     // They should be switched to passing null and using setDocumentForAnonymous.
    156     if (node && node->isDocumentNode())
    157         setDocumentForAnonymous(toDocument(node));
    158 
    159     m_isAllASCII = m_text.containsOnlyASCII();
    160     m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
    161     setIsText();
    162 
    163     view()->frameView()->incrementVisuallyNonEmptyCharacterCount(m_text.length());
    164 }
    165 
    166 #ifndef NDEBUG
    167 
    168 RenderText::~RenderText()
    169 {
    170     ASSERT(!m_firstTextBox);
    171     ASSERT(!m_lastTextBox);
    172 }
    173 
    174 #endif
    175 
    176 const char* RenderText::renderName() const
    177 {
    178     return "RenderText";
    179 }
    180 
    181 bool RenderText::isTextFragment() const
    182 {
    183     return false;
    184 }
    185 
    186 bool RenderText::isWordBreak() const
    187 {
    188     return false;
    189 }
    190 
    191 void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
    192 {
    193     // There is no need to ever schedule repaints from a style change of a text run, since
    194     // we already did this for the parent of the text run.
    195     // We do have to schedule layouts, though, since a style change can force us to
    196     // need to relayout.
    197     if (diff.needsFullLayout()) {
    198         setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
    199         m_knownToHaveNoOverflowAndNoFallbackFonts = false;
    200     }
    201 
    202     RenderStyle* newStyle = style();
    203     ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
    204     ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
    205     if (oldTransform != newStyle->textTransform() || oldSecurity != newStyle->textSecurity())
    206         transformText();
    207 
    208     // This is an optimization that kicks off font load before layout.
    209     // In order to make it fast, we only check if the first character of the
    210     // text is included in the unicode ranges of the fonts.
    211     if (!text().containsOnlyWhitespace())
    212         newStyle->font().willUseFontData(text().characterStartingAt(0));
    213 }
    214 
    215 void RenderText::removeAndDestroyTextBoxes()
    216 {
    217     if (!documentBeingDestroyed()) {
    218         if (firstTextBox()) {
    219             if (isBR()) {
    220                 RootInlineBox* next = firstTextBox()->root().nextRootBox();
    221                 if (next)
    222                     next->markDirty();
    223             }
    224             for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
    225                 box->remove();
    226         } else if (parent())
    227             parent()->dirtyLinesFromChangedChild(this);
    228     }
    229     deleteTextBoxes();
    230 }
    231 
    232 void RenderText::willBeDestroyed()
    233 {
    234     if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->take(this) : 0)
    235         delete secureTextTimer;
    236 
    237     removeAndDestroyTextBoxes();
    238     RenderObject::willBeDestroyed();
    239 }
    240 
    241 void RenderText::extractTextBox(InlineTextBox* box)
    242 {
    243     checkConsistency();
    244 
    245     m_lastTextBox = box->prevTextBox();
    246     if (box == m_firstTextBox)
    247         m_firstTextBox = 0;
    248     if (box->prevTextBox())
    249         box->prevTextBox()->setNextTextBox(0);
    250     box->setPreviousTextBox(0);
    251     for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox())
    252         curr->setExtracted();
    253 
    254     checkConsistency();
    255 }
    256 
    257 void RenderText::attachTextBox(InlineTextBox* box)
    258 {
    259     checkConsistency();
    260 
    261     if (m_lastTextBox) {
    262         m_lastTextBox->setNextTextBox(box);
    263         box->setPreviousTextBox(m_lastTextBox);
    264     } else
    265         m_firstTextBox = box;
    266     InlineTextBox* last = box;
    267     for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {
    268         curr->setExtracted(false);
    269         last = curr;
    270     }
    271     m_lastTextBox = last;
    272 
    273     checkConsistency();
    274 }
    275 
    276 void RenderText::removeTextBox(InlineTextBox* box)
    277 {
    278     checkConsistency();
    279 
    280     if (box == m_firstTextBox)
    281         m_firstTextBox = box->nextTextBox();
    282     if (box == m_lastTextBox)
    283         m_lastTextBox = box->prevTextBox();
    284     if (box->nextTextBox())
    285         box->nextTextBox()->setPreviousTextBox(box->prevTextBox());
    286     if (box->prevTextBox())
    287         box->prevTextBox()->setNextTextBox(box->nextTextBox());
    288 
    289     checkConsistency();
    290 }
    291 
    292 void RenderText::deleteTextBoxes()
    293 {
    294     if (firstTextBox()) {
    295         InlineTextBox* next;
    296         for (InlineTextBox* curr = firstTextBox(); curr; curr = next) {
    297             next = curr->nextTextBox();
    298             curr->destroy();
    299         }
    300         m_firstTextBox = m_lastTextBox = 0;
    301     }
    302 }
    303 
    304 PassRefPtr<StringImpl> RenderText::originalText() const
    305 {
    306     Node* e = node();
    307     return (e && e->isTextNode()) ? toText(e)->dataImpl() : 0;
    308 }
    309 
    310 String RenderText::plainText() const
    311 {
    312     if (node())
    313         return WebCore::plainText(rangeOfContents(node()).get());
    314 
    315     // FIXME: this is just a stopgap until TextIterator is adapted to support generated text.
    316     StringBuilder plainTextBuilder;
    317     for (InlineTextBox* textBox = firstTextBox(); textBox; textBox = textBox->nextTextBox()) {
    318         String text = m_text.substring(textBox->start(), textBox->len()).simplifyWhiteSpace(WTF::DoNotStripWhiteSpace);
    319         plainTextBuilder.append(text);
    320         if (textBox->nextTextBox() && textBox->nextTextBox()->start() > textBox->end() && text.length() && !text.right(1).containsOnlyWhitespace())
    321             plainTextBuilder.append(" ");
    322     }
    323     return plainTextBuilder.toString();
    324 }
    325 
    326 void RenderText::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
    327 {
    328     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
    329         rects.append(enclosingIntRect(FloatRect(accumulatedOffset + box->topLeft(), box->size())));
    330 }
    331 
    332 static FloatRect localQuadForTextBox(InlineTextBox* box, unsigned start, unsigned end, bool useSelectionHeight)
    333 {
    334     unsigned realEnd = min(box->end() + 1, end);
    335     LayoutRect r = box->localSelectionRect(start, realEnd);
    336     if (r.height()) {
    337         if (!useSelectionHeight) {
    338             // Change the height and y position (or width and x for vertical text)
    339             // because selectionRect uses selection-specific values.
    340             if (box->isHorizontal()) {
    341                 r.setHeight(box->height());
    342                 r.setY(box->y());
    343             } else {
    344                 r.setWidth(box->width());
    345                 r.setX(box->x());
    346             }
    347         }
    348         return FloatRect(r);
    349     }
    350     return FloatRect();
    351 }
    352 
    353 void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
    354 {
    355     // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
    356     // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
    357     // function to take ints causes various internal mismatches. But selectionRect takes ints, and
    358     // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
    359     // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
    360     ASSERT(end == UINT_MAX || end <= INT_MAX);
    361     ASSERT(start <= INT_MAX);
    362     start = min(start, static_cast<unsigned>(INT_MAX));
    363     end = min(end, static_cast<unsigned>(INT_MAX));
    364 
    365     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
    366         // Note: box->end() returns the index of the last character, not the index past it
    367         if (start <= box->start() && box->end() < end) {
    368             FloatRect r = box->calculateBoundaries();
    369             if (useSelectionHeight) {
    370                 LayoutRect selectionRect = box->localSelectionRect(start, end);
    371                 if (box->isHorizontal()) {
    372                     r.setHeight(selectionRect.height().toFloat());
    373                     r.setY(selectionRect.y().toFloat());
    374                 } else {
    375                     r.setWidth(selectionRect.width().toFloat());
    376                     r.setX(selectionRect.x().toFloat());
    377                 }
    378             }
    379             rects.append(localToAbsoluteQuad(r, 0, wasFixed).enclosingBoundingBox());
    380         } else {
    381             // FIXME: This code is wrong. It's converting local to absolute twice. http://webkit.org/b/65722
    382             FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
    383             if (!rect.isZero())
    384                 rects.append(localToAbsoluteQuad(rect, 0, wasFixed).enclosingBoundingBox());
    385         }
    386     }
    387 }
    388 
    389 static IntRect ellipsisRectForBox(InlineTextBox* box, unsigned startPos, unsigned endPos)
    390 {
    391     if (!box)
    392         return IntRect();
    393 
    394     unsigned short truncation = box->truncation();
    395     if (truncation == cNoTruncation)
    396         return IntRect();
    397 
    398     IntRect rect;
    399     if (EllipsisBox* ellipsis = box->root().ellipsisBox()) {
    400         int ellipsisStartPosition = max<int>(startPos - box->start(), 0);
    401         int ellipsisEndPosition = min<int>(endPos - box->start(), box->len());
    402 
    403         // The ellipsis should be considered to be selected if the end of
    404         // the selection is past the beginning of the truncation and the
    405         // beginning of the selection is before or at the beginning of the truncation.
    406         if (ellipsisEndPosition >= truncation && ellipsisStartPosition <= truncation)
    407             return ellipsis->selectionRect();
    408     }
    409 
    410     return IntRect();
    411 }
    412 
    413 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed, ClippingOption option) const
    414 {
    415     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
    416         FloatRect boundaries = box->calculateBoundaries();
    417 
    418         // Shorten the width of this text box if it ends in an ellipsis.
    419         // FIXME: ellipsisRectForBox should switch to return FloatRect soon with the subpixellayout branch.
    420         IntRect ellipsisRect = (option == ClipToEllipsis) ? ellipsisRectForBox(box, 0, textLength()) : IntRect();
    421         if (!ellipsisRect.isEmpty()) {
    422             if (style()->isHorizontalWritingMode())
    423                 boundaries.setWidth(ellipsisRect.maxX() - boundaries.x());
    424             else
    425                 boundaries.setHeight(ellipsisRect.maxY() - boundaries.y());
    426         }
    427         quads.append(localToAbsoluteQuad(boundaries, 0, wasFixed));
    428     }
    429 }
    430 
    431 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
    432 {
    433     absoluteQuads(quads, wasFixed, NoClipping);
    434 }
    435 
    436 void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
    437 {
    438     // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
    439     // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
    440     // function to take ints causes various internal mismatches. But selectionRect takes ints, and
    441     // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
    442     // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
    443     ASSERT(end == UINT_MAX || end <= INT_MAX);
    444     ASSERT(start <= INT_MAX);
    445     start = min(start, static_cast<unsigned>(INT_MAX));
    446     end = min(end, static_cast<unsigned>(INT_MAX));
    447 
    448     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
    449         // Note: box->end() returns the index of the last character, not the index past it
    450         if (start <= box->start() && box->end() < end) {
    451             FloatRect r = box->calculateBoundaries();
    452             if (useSelectionHeight) {
    453                 LayoutRect selectionRect = box->localSelectionRect(start, end);
    454                 if (box->isHorizontal()) {
    455                     r.setHeight(selectionRect.height().toFloat());
    456                     r.setY(selectionRect.y().toFloat());
    457                 } else {
    458                     r.setWidth(selectionRect.width().toFloat());
    459                     r.setX(selectionRect.x().toFloat());
    460                 }
    461             }
    462             quads.append(localToAbsoluteQuad(r, 0, wasFixed));
    463         } else {
    464             FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
    465             if (!rect.isZero())
    466                 quads.append(localToAbsoluteQuad(rect, 0, wasFixed));
    467         }
    468     }
    469 }
    470 
    471 enum ShouldAffinityBeDownstream { AlwaysDownstream, AlwaysUpstream, UpstreamIfPositionIsNotAtStart };
    472 
    473 static bool lineDirectionPointFitsInBox(int pointLineDirection, InlineTextBox* box, ShouldAffinityBeDownstream& shouldAffinityBeDownstream)
    474 {
    475     shouldAffinityBeDownstream = AlwaysDownstream;
    476 
    477     // the x coordinate is equal to the left edge of this box
    478     // the affinity must be downstream so the position doesn't jump back to the previous line
    479     // except when box is the first box in the line
    480     if (pointLineDirection <= box->logicalLeft()) {
    481         shouldAffinityBeDownstream = !box->prevLeafChild() ? UpstreamIfPositionIsNotAtStart : AlwaysDownstream;
    482         return true;
    483     }
    484 
    485     // and the x coordinate is to the left of the right edge of this box
    486     // check to see if position goes in this box
    487     if (pointLineDirection < box->logicalRight()) {
    488         shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
    489         return true;
    490     }
    491 
    492     // box is first on line
    493     // and the x coordinate is to the left of the first text box left edge
    494     if (!box->prevLeafChildIgnoringLineBreak() && pointLineDirection < box->logicalLeft())
    495         return true;
    496 
    497     if (!box->nextLeafChildIgnoringLineBreak()) {
    498         // box is last on line
    499         // and the x coordinate is to the right of the last text box right edge
    500         // generate VisiblePosition, use UPSTREAM affinity if possible
    501         shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
    502         return true;
    503     }
    504 
    505     return false;
    506 }
    507 
    508 static PositionWithAffinity createPositionWithAffinityForBox(const InlineBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
    509 {
    510     EAffinity affinity = VP_DEFAULT_AFFINITY;
    511     switch (shouldAffinityBeDownstream) {
    512     case AlwaysDownstream:
    513         affinity = DOWNSTREAM;
    514         break;
    515     case AlwaysUpstream:
    516         affinity = VP_UPSTREAM_IF_POSSIBLE;
    517         break;
    518     case UpstreamIfPositionIsNotAtStart:
    519         affinity = offset > box->caretMinOffset() ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM;
    520         break;
    521     }
    522     int textStartOffset = box->renderer().isText() ? toRenderText(box->renderer()).textStartOffset() : 0;
    523     return box->renderer().createPositionWithAffinity(offset + textStartOffset, affinity);
    524 }
    525 
    526 static PositionWithAffinity createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(const InlineTextBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
    527 {
    528     ASSERT(box);
    529     ASSERT(offset >= 0);
    530 
    531     if (offset && static_cast<unsigned>(offset) < box->len())
    532         return createPositionWithAffinityForBox(box, box->start() + offset, shouldAffinityBeDownstream);
    533 
    534     bool positionIsAtStartOfBox = !offset;
    535     if (positionIsAtStartOfBox == box->isLeftToRightDirection()) {
    536         // offset is on the left edge
    537 
    538         const InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak();
    539         if ((prevBox && prevBox->bidiLevel() == box->bidiLevel())
    540             || box->renderer().containingBlock()->style()->direction() == box->direction()) // FIXME: left on 12CBA
    541             return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
    542 
    543         if (prevBox && prevBox->bidiLevel() > box->bidiLevel()) {
    544             // e.g. left of B in aDC12BAb
    545             const InlineBox* leftmostBox;
    546             do {
    547                 leftmostBox = prevBox;
    548                 prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
    549             } while (prevBox && prevBox->bidiLevel() > box->bidiLevel());
    550             return createPositionWithAffinityForBox(leftmostBox, leftmostBox->caretRightmostOffset(), shouldAffinityBeDownstream);
    551         }
    552 
    553         if (!prevBox || prevBox->bidiLevel() < box->bidiLevel()) {
    554             // e.g. left of D in aDC12BAb
    555             const InlineBox* rightmostBox;
    556             const InlineBox* nextBox = box;
    557             do {
    558                 rightmostBox = nextBox;
    559                 nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
    560             } while (nextBox && nextBox->bidiLevel() >= box->bidiLevel());
    561             return createPositionWithAffinityForBox(rightmostBox,
    562                 box->isLeftToRightDirection() ? rightmostBox->caretMaxOffset() : rightmostBox->caretMinOffset(), shouldAffinityBeDownstream);
    563         }
    564 
    565         return createPositionWithAffinityForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
    566     }
    567 
    568     const InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak();
    569     if ((nextBox && nextBox->bidiLevel() == box->bidiLevel())
    570         || box->renderer().containingBlock()->style()->direction() == box->direction())
    571         return createPositionWithAffinityForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
    572 
    573     // offset is on the right edge
    574     if (nextBox && nextBox->bidiLevel() > box->bidiLevel()) {
    575         // e.g. right of C in aDC12BAb
    576         const InlineBox* rightmostBox;
    577         do {
    578             rightmostBox = nextBox;
    579             nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
    580         } while (nextBox && nextBox->bidiLevel() > box->bidiLevel());
    581         return createPositionWithAffinityForBox(rightmostBox, rightmostBox->caretLeftmostOffset(), shouldAffinityBeDownstream);
    582     }
    583 
    584     if (!nextBox || nextBox->bidiLevel() < box->bidiLevel()) {
    585         // e.g. right of A in aDC12BAb
    586         const InlineBox* leftmostBox;
    587         const InlineBox* prevBox = box;
    588         do {
    589             leftmostBox = prevBox;
    590             prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
    591         } while (prevBox && prevBox->bidiLevel() >= box->bidiLevel());
    592         return createPositionWithAffinityForBox(leftmostBox,
    593             box->isLeftToRightDirection() ? leftmostBox->caretMinOffset() : leftmostBox->caretMaxOffset(), shouldAffinityBeDownstream);
    594     }
    595 
    596     return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
    597 }
    598 
    599 PositionWithAffinity RenderText::positionForPoint(const LayoutPoint& point)
    600 {
    601     if (!firstTextBox() || textLength() == 0)
    602         return createPositionWithAffinity(0, DOWNSTREAM);
    603 
    604     LayoutUnit pointLineDirection = firstTextBox()->isHorizontal() ? point.x() : point.y();
    605     LayoutUnit pointBlockDirection = firstTextBox()->isHorizontal() ? point.y() : point.x();
    606     bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
    607 
    608     InlineTextBox* lastBox = 0;
    609     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
    610         if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild() && !box->nextLeafChild()->isLineBreak())
    611             box = box->nextTextBox();
    612 
    613         RootInlineBox& rootBox = box->root();
    614         LayoutUnit top = min(rootBox.selectionTop(), rootBox.lineTop());
    615         if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirection == top)) {
    616             LayoutUnit bottom = rootBox.selectionBottom();
    617             if (rootBox.nextRootBox())
    618                 bottom = min(bottom, rootBox.nextRootBox()->lineTop());
    619 
    620             if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockDirection == bottom)) {
    621                 ShouldAffinityBeDownstream shouldAffinityBeDownstream;
    622                 if (lineDirectionPointFitsInBox(pointLineDirection, box, shouldAffinityBeDownstream))
    623                     return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(box, box->offsetForPosition(pointLineDirection.toFloat()), shouldAffinityBeDownstream);
    624             }
    625         }
    626         lastBox = box;
    627     }
    628 
    629     if (lastBox) {
    630         ShouldAffinityBeDownstream shouldAffinityBeDownstream;
    631         lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityBeDownstream);
    632         return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastBox, lastBox->offsetForPosition(pointLineDirection.toFloat()) + lastBox->start(), shouldAffinityBeDownstream);
    633     }
    634     return createPositionWithAffinity(0, DOWNSTREAM);
    635 }
    636 
    637 LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
    638 {
    639     if (!inlineBox)
    640         return LayoutRect();
    641 
    642     ASSERT(inlineBox->isInlineTextBox());
    643     if (!inlineBox->isInlineTextBox())
    644         return LayoutRect();
    645 
    646     InlineTextBox* box = toInlineTextBox(inlineBox);
    647 
    648     int height = box->root().selectionHeight();
    649     int top = box->root().selectionTop();
    650 
    651     // Go ahead and round left to snap it to the nearest pixel.
    652     float left = box->positionForOffset(caretOffset);
    653 
    654     // Distribute the caret's width to either side of the offset.
    655     int caretWidthLeftOfOffset = caretWidth / 2;
    656     left -= caretWidthLeftOfOffset;
    657     int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset;
    658 
    659     left = roundf(left);
    660 
    661     float rootLeft = box->root().logicalLeft();
    662     float rootRight = box->root().logicalRight();
    663 
    664     // FIXME: should we use the width of the root inline box or the
    665     // width of the containing block for this?
    666     if (extraWidthToEndOfLine)
    667         *extraWidthToEndOfLine = (box->root().logicalWidth() + rootLeft) - (left + 1);
    668 
    669     RenderBlock* cb = containingBlock();
    670     RenderStyle* cbStyle = cb->style();
    671 
    672     float leftEdge;
    673     float rightEdge;
    674     leftEdge = min<float>(0, rootLeft);
    675     rightEdge = max<float>(cb->logicalWidth().toFloat(), rootRight);
    676 
    677     bool rightAligned = false;
    678     switch (cbStyle->textAlign()) {
    679     case RIGHT:
    680     case WEBKIT_RIGHT:
    681         rightAligned = true;
    682         break;
    683     case LEFT:
    684     case WEBKIT_LEFT:
    685     case CENTER:
    686     case WEBKIT_CENTER:
    687         break;
    688     case JUSTIFY:
    689     case TASTART:
    690         rightAligned = !cbStyle->isLeftToRightDirection();
    691         break;
    692     case TAEND:
    693         rightAligned = cbStyle->isLeftToRightDirection();
    694         break;
    695     }
    696 
    697     if (rightAligned) {
    698         left = max(left, leftEdge);
    699         left = min(left, rootRight - caretWidth);
    700     } else {
    701         left = min(left, rightEdge - caretWidthRightOfOffset);
    702         left = max(left, rootLeft);
    703     }
    704 
    705     return style()->isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth);
    706 }
    707 
    708 ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
    709 {
    710     if (style()->hasTextCombine() && isCombineText()) {
    711         const RenderCombineText* combineText = toRenderCombineText(this);
    712         if (combineText->isCombined())
    713             return combineText->combinedTextWidth(f);
    714     }
    715 
    716     if (f.isFixedPitch() && f.fontDescription().variant() == FontVariantNormal && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
    717         float monospaceCharacterWidth = f.spaceWidth();
    718         float w = 0;
    719         bool isSpace;
    720         ASSERT(m_text);
    721         StringImpl& text = *m_text.impl();
    722         for (int i = start; i < start + len; i++) {
    723             char c = text[i];
    724             if (c <= ' ') {
    725                 if (c == ' ' || c == '\n') {
    726                     w += monospaceCharacterWidth;
    727                     isSpace = true;
    728                 } else if (c == '\t') {
    729                     if (style()->collapseWhiteSpace()) {
    730                         w += monospaceCharacterWidth;
    731                         isSpace = true;
    732                     } else {
    733                         w += f.tabWidth(style()->tabSize(), xPos + w);
    734                         isSpace = false;
    735                     }
    736                 } else
    737                     isSpace = false;
    738             } else {
    739                 w += monospaceCharacterWidth;
    740                 isSpace = false;
    741             }
    742             if (isSpace && i > start)
    743                 w += f.fontDescription().wordSpacing();
    744         }
    745         return w;
    746     }
    747 
    748     TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, start, len, style(), textDirection);
    749     run.setCharactersLength(textLength() - start);
    750     ASSERT(run.charactersLength() >= run.length());
    751 
    752     run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
    753     run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
    754     run.setXPos(xPos);
    755     FontCachePurgePreventer fontCachePurgePreventer;
    756     return f.width(run, fallbackFonts, glyphOverflow);
    757 }
    758 
    759 void RenderText::trimmedPrefWidths(float leadWidth,
    760     float& firstLineMinWidth, bool& hasBreakableStart,
    761     float& lastLineMinWidth, bool& hasBreakableEnd,
    762     bool& hasBreakableChar, bool& hasBreak,
    763     float& firstLineMaxWidth, float& lastLineMaxWidth,
    764     float& minWidth, float& maxWidth, bool& stripFrontSpaces,
    765     TextDirection direction)
    766 {
    767     bool collapseWhiteSpace = style()->collapseWhiteSpace();
    768     if (!collapseWhiteSpace)
    769         stripFrontSpaces = false;
    770 
    771     if (m_hasTab || preferredLogicalWidthsDirty())
    772         computePreferredLogicalWidths(leadWidth);
    773 
    774     hasBreakableStart = !stripFrontSpaces && m_hasBreakableStart;
    775     hasBreakableEnd = m_hasBreakableEnd;
    776 
    777     int len = textLength();
    778 
    779     if (!len || (stripFrontSpaces && text().impl()->containsOnlyWhitespace())) {
    780         firstLineMinWidth = 0;
    781         lastLineMinWidth = 0;
    782         firstLineMaxWidth = 0;
    783         lastLineMaxWidth = 0;
    784         minWidth = 0;
    785         maxWidth = 0;
    786         hasBreak = false;
    787         return;
    788     }
    789 
    790     minWidth = m_minWidth;
    791     maxWidth = m_maxWidth;
    792 
    793     firstLineMinWidth = m_firstLineMinWidth;
    794     lastLineMinWidth = m_lastLineLineMinWidth;
    795 
    796     hasBreakableChar = m_hasBreakableChar;
    797     hasBreak = m_hasBreak;
    798 
    799     ASSERT(m_text);
    800     StringImpl& text = *m_text.impl();
    801     if (text[0] == ' ' || (text[0] == '\n' && !style()->preserveNewline()) || text[0] == '\t') {
    802         const Font& font = style()->font(); // FIXME: This ignores first-line.
    803         if (stripFrontSpaces) {
    804             const UChar space = ' ';
    805             float spaceWidth = font.width(RenderBlockFlow::constructTextRun(this, font, &space, 1, style(), direction));
    806             maxWidth -= spaceWidth;
    807         } else {
    808             maxWidth += font.fontDescription().wordSpacing();
    809         }
    810     }
    811 
    812     stripFrontSpaces = collapseWhiteSpace && m_hasEndWhiteSpace;
    813 
    814     if (!style()->autoWrap() || minWidth > maxWidth)
    815         minWidth = maxWidth;
    816 
    817     // Compute our max widths by scanning the string for newlines.
    818     if (hasBreak) {
    819         const Font& f = style()->font(); // FIXME: This ignores first-line.
    820         bool firstLine = true;
    821         firstLineMaxWidth = maxWidth;
    822         lastLineMaxWidth = maxWidth;
    823         for (int i = 0; i < len; i++) {
    824             int linelen = 0;
    825             while (i + linelen < len && text[i + linelen] != '\n')
    826                 linelen++;
    827 
    828             if (linelen) {
    829                 lastLineMaxWidth = widthFromCache(f, i, linelen, leadWidth + lastLineMaxWidth, direction, 0, 0);
    830                 if (firstLine) {
    831                     firstLine = false;
    832                     leadWidth = 0;
    833                     firstLineMaxWidth = lastLineMaxWidth;
    834                 }
    835                 i += linelen;
    836             } else if (firstLine) {
    837                 firstLineMaxWidth = 0;
    838                 firstLine = false;
    839                 leadWidth = 0;
    840             }
    841 
    842             if (i == len - 1) {
    843                 // A <pre> run that ends with a newline, as in, e.g.,
    844                 // <pre>Some text\n\n<span>More text</pre>
    845                 lastLineMaxWidth = 0;
    846             }
    847         }
    848     }
    849 }
    850 
    851 float RenderText::minLogicalWidth() const
    852 {
    853     if (preferredLogicalWidthsDirty())
    854         const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
    855 
    856     return m_minWidth;
    857 }
    858 
    859 float RenderText::maxLogicalWidth() const
    860 {
    861     if (preferredLogicalWidthsDirty())
    862         const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
    863 
    864     return m_maxWidth;
    865 }
    866 
    867 void RenderText::computePreferredLogicalWidths(float leadWidth)
    868 {
    869     HashSet<const SimpleFontData*> fallbackFonts;
    870     GlyphOverflow glyphOverflow;
    871     computePreferredLogicalWidths(leadWidth, fallbackFonts, glyphOverflow);
    872     if (fallbackFonts.isEmpty() && !glyphOverflow.left && !glyphOverflow.right && !glyphOverflow.top && !glyphOverflow.bottom)
    873         m_knownToHaveNoOverflowAndNoFallbackFonts = true;
    874 }
    875 
    876 static inline float hyphenWidth(RenderText* renderer, const Font& font, TextDirection direction)
    877 {
    878     RenderStyle* style = renderer->style();
    879     return font.width(RenderBlockFlow::constructTextRun(renderer, font, style->hyphenString().string(), style, direction));
    880 }
    881 
    882 void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
    883 {
    884     ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts);
    885 
    886     m_minWidth = 0;
    887     m_maxWidth = 0;
    888     m_firstLineMinWidth = 0;
    889     m_lastLineLineMinWidth = 0;
    890 
    891     if (isBR())
    892         return;
    893 
    894     float currMinWidth = 0;
    895     float currMaxWidth = 0;
    896     m_hasBreakableChar = false;
    897     m_hasBreak = false;
    898     m_hasTab = false;
    899     m_hasBreakableStart = false;
    900     m_hasBreakableEnd = false;
    901     m_hasEndWhiteSpace = false;
    902 
    903     RenderStyle* styleToUse = style();
    904     const Font& f = styleToUse->font(); // FIXME: This ignores first-line.
    905     float wordSpacing = styleToUse->wordSpacing();
    906     int len = textLength();
    907     LazyLineBreakIterator breakIterator(m_text, styleToUse->locale());
    908     bool needsWordSpacing = false;
    909     bool ignoringSpaces = false;
    910     bool isSpace = false;
    911     bool firstWord = true;
    912     bool firstLine = true;
    913     int nextBreakable = -1;
    914     int lastWordBoundary = 0;
    915     float cachedWordTrailingSpaceWidth[2] = { 0, 0 }; // LTR, RTL
    916 
    917     int firstGlyphLeftOverflow = -1;
    918 
    919     bool breakAll = (styleToUse->wordBreak() == BreakAllWordBreak || styleToUse->wordBreak() == BreakWordBreak) && styleToUse->autoWrap();
    920 
    921     TextRun textRun(text());
    922     BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    923 
    924     BidiCharacterRun* run;
    925     TextDirection textDirection = styleToUse->direction();
    926     if (isOverride(styleToUse->unicodeBidi())) {
    927         run = 0;
    928     } else {
    929         BidiStatus status(LTR, false);
    930         status.last = status.lastStrong = WTF::Unicode::OtherNeutral;
    931         bidiResolver.setStatus(status);
    932         bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&textRun, 0));
    933         bool hardLineBreak = false;
    934         bool reorderRuns = false;
    935         bidiResolver.createBidiRunsForLine(TextRunIterator(&textRun, textRun.length()), NoVisualOverride, hardLineBreak, reorderRuns);
    936         BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
    937         run = bidiRuns.firstRun();
    938     }
    939 
    940     for (int i = 0; i < len; i++) {
    941         UChar c = uncheckedCharacterAt(i);
    942 
    943         if (run) {
    944             // Treat adjacent runs with the same resolved directionality
    945             // (TextDirection as opposed to WTF::Unicode::Direction) as belonging
    946             // to the same run to avoid breaking unnecessarily.
    947             while (i > run->stop() || (run->next() && run->next()->direction() == run->direction()))
    948                 run = run->next();
    949 
    950             ASSERT(run);
    951             ASSERT(i <= run->stop());
    952             textDirection = run->direction();
    953         }
    954 
    955         bool previousCharacterIsSpace = isSpace;
    956         bool isNewline = false;
    957         if (c == '\n') {
    958             if (styleToUse->preserveNewline()) {
    959                 m_hasBreak = true;
    960                 isNewline = true;
    961                 isSpace = false;
    962             } else
    963                 isSpace = true;
    964         } else if (c == '\t') {
    965             if (!styleToUse->collapseWhiteSpace()) {
    966                 m_hasTab = true;
    967                 isSpace = false;
    968             } else
    969                 isSpace = true;
    970         } else
    971             isSpace = c == ' ';
    972 
    973         bool isBreakableLocation = isNewline || (isSpace && styleToUse->autoWrap());
    974         if (!i)
    975             m_hasBreakableStart = isBreakableLocation;
    976         if (i == len - 1) {
    977             m_hasBreakableEnd = isBreakableLocation;
    978             m_hasEndWhiteSpace = isNewline || isSpace;
    979         }
    980 
    981         if (!ignoringSpaces && styleToUse->collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
    982             ignoringSpaces = true;
    983 
    984         if (ignoringSpaces && !isSpace)
    985             ignoringSpaces = false;
    986 
    987         // Ignore spaces and soft hyphens
    988         if (ignoringSpaces) {
    989             ASSERT(lastWordBoundary == i);
    990             lastWordBoundary++;
    991             continue;
    992         } else if (c == softHyphen) {
    993             currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
    994             if (firstGlyphLeftOverflow < 0)
    995                 firstGlyphLeftOverflow = glyphOverflow.left;
    996             lastWordBoundary = i + 1;
    997             continue;
    998         }
    999 
   1000         bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable);
   1001         bool betweenWords = true;
   1002         int j = i;
   1003         while (c != '\n' && c != ' ' && c != '\t' && (c != softHyphen)) {
   1004             j++;
   1005             if (j == len)
   1006                 break;
   1007             c = uncheckedCharacterAt(j);
   1008             if (isBreakable(breakIterator, j, nextBreakable) && characterAt(j - 1) != softHyphen)
   1009                 break;
   1010             if (breakAll) {
   1011                 betweenWords = false;
   1012                 break;
   1013             }
   1014         }
   1015 
   1016         // Terminate word boundary at bidi run boundary.
   1017         if (run)
   1018             j = min(j, run->stop() + 1);
   1019         int wordLen = j - i;
   1020         if (wordLen) {
   1021             bool isSpace = (j < len) && c == ' ';
   1022 
   1023             // Non-zero only when kerning is enabled, in which case we measure words with their trailing
   1024             // space, then subtract its width.
   1025             float wordTrailingSpaceWidth = 0;
   1026             if (isSpace && (f.fontDescription().typesettingFeatures() & Kerning)) {
   1027                 ASSERT(textDirection >=0 && textDirection <= 1);
   1028                 if (!cachedWordTrailingSpaceWidth[textDirection])
   1029                     cachedWordTrailingSpaceWidth[textDirection] = f.width(RenderBlockFlow::constructTextRun(this, f, &space, 1, styleToUse, textDirection)) + wordSpacing;
   1030                 wordTrailingSpaceWidth = cachedWordTrailingSpaceWidth[textDirection];
   1031             }
   1032 
   1033             float w;
   1034             if (wordTrailingSpaceWidth && isSpace)
   1035                 w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth;
   1036             else {
   1037                 w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
   1038                 if (c == softHyphen)
   1039                     currMinWidth += hyphenWidth(this, f, textDirection);
   1040             }
   1041 
   1042             if (firstGlyphLeftOverflow < 0)
   1043                 firstGlyphLeftOverflow = glyphOverflow.left;
   1044             currMinWidth += w;
   1045             if (betweenWords) {
   1046                 if (lastWordBoundary == i)
   1047                     currMaxWidth += w;
   1048                 else
   1049                     currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
   1050                 lastWordBoundary = j;
   1051             }
   1052 
   1053             bool isCollapsibleWhiteSpace = (j < len) && styleToUse->isCollapsibleWhiteSpace(c);
   1054             if (j < len && styleToUse->autoWrap())
   1055                 m_hasBreakableChar = true;
   1056 
   1057             // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
   1058             // last word in the run.
   1059             if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
   1060                 currMaxWidth += wordSpacing;
   1061 
   1062             if (firstWord) {
   1063                 firstWord = false;
   1064                 // If the first character in the run is breakable, then we consider ourselves to have a beginning
   1065                 // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
   1066                 // being appended to a previous text run when considering the total minimum width of the containing block.
   1067                 if (hasBreak)
   1068                     m_hasBreakableChar = true;
   1069                 m_firstLineMinWidth = hasBreak ? 0 : currMinWidth;
   1070             }
   1071             m_lastLineLineMinWidth = currMinWidth;
   1072 
   1073             if (currMinWidth > m_minWidth)
   1074                 m_minWidth = currMinWidth;
   1075             currMinWidth = 0;
   1076 
   1077             i += wordLen - 1;
   1078         } else {
   1079             // Nowrap can never be broken, so don't bother setting the
   1080             // breakable character boolean. Pre can only be broken if we encounter a newline.
   1081             if (style()->autoWrap() || isNewline)
   1082                 m_hasBreakableChar = true;
   1083 
   1084             if (currMinWidth > m_minWidth)
   1085                 m_minWidth = currMinWidth;
   1086             currMinWidth = 0;
   1087 
   1088             if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
   1089                 if (firstLine) {
   1090                     firstLine = false;
   1091                     leadWidth = 0;
   1092                     if (!styleToUse->autoWrap())
   1093                         m_firstLineMinWidth = currMaxWidth;
   1094                 }
   1095 
   1096                 if (currMaxWidth > m_maxWidth)
   1097                     m_maxWidth = currMaxWidth;
   1098                 currMaxWidth = 0;
   1099             } else {
   1100                 TextRun run = RenderBlockFlow::constructTextRun(this, f, this, i, 1, styleToUse, textDirection);
   1101                 run.setCharactersLength(len - i);
   1102                 ASSERT(run.charactersLength() >= run.length());
   1103                 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
   1104                 run.setXPos(leadWidth + currMaxWidth);
   1105 
   1106                 currMaxWidth += f.width(run);
   1107                 glyphOverflow.right = 0;
   1108                 needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
   1109             }
   1110             ASSERT(lastWordBoundary == i);
   1111             lastWordBoundary++;
   1112         }
   1113     }
   1114     if (run)
   1115         bidiResolver.runs().deleteRuns();
   1116 
   1117     if (firstGlyphLeftOverflow > 0)
   1118         glyphOverflow.left = firstGlyphLeftOverflow;
   1119 
   1120     if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord))
   1121         currMaxWidth += wordSpacing;
   1122 
   1123     m_minWidth = max(currMinWidth, m_minWidth);
   1124     m_maxWidth = max(currMaxWidth, m_maxWidth);
   1125 
   1126     if (!styleToUse->autoWrap())
   1127         m_minWidth = m_maxWidth;
   1128 
   1129     if (styleToUse->whiteSpace() == PRE) {
   1130         if (firstLine)
   1131             m_firstLineMinWidth = m_maxWidth;
   1132         m_lastLineLineMinWidth = currMaxWidth;
   1133     }
   1134 
   1135     clearPreferredLogicalWidthsDirty();
   1136 }
   1137 
   1138 bool RenderText::isAllCollapsibleWhitespace() const
   1139 {
   1140     unsigned length = textLength();
   1141     if (is8Bit()) {
   1142         for (unsigned i = 0; i < length; ++i) {
   1143             if (!style()->isCollapsibleWhiteSpace(characters8()[i]))
   1144                 return false;
   1145         }
   1146         return true;
   1147     }
   1148     for (unsigned i = 0; i < length; ++i) {
   1149         if (!style()->isCollapsibleWhiteSpace(characters16()[i]))
   1150             return false;
   1151     }
   1152     return true;
   1153 }
   1154 
   1155 bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
   1156 {
   1157     ASSERT(m_text);
   1158     StringImpl& text = *m_text.impl();
   1159     unsigned currPos;
   1160     for (currPos = from;
   1161          currPos < from + len && (text[currPos] == '\n' || text[currPos] == ' ' || text[currPos] == '\t');
   1162          currPos++) { }
   1163     return currPos >= (from + len);
   1164 }
   1165 
   1166 FloatPoint RenderText::firstRunOrigin() const
   1167 {
   1168     return IntPoint(firstRunX(), firstRunY());
   1169 }
   1170 
   1171 float RenderText::firstRunX() const
   1172 {
   1173     return m_firstTextBox ? m_firstTextBox->x() : 0;
   1174 }
   1175 
   1176 float RenderText::firstRunY() const
   1177 {
   1178     return m_firstTextBox ? m_firstTextBox->y() : 0;
   1179 }
   1180 
   1181 void RenderText::setSelectionState(SelectionState state)
   1182 {
   1183     RenderObject::setSelectionState(state);
   1184 
   1185     if (canUpdateSelectionOnRootLineBoxes()) {
   1186         if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) {
   1187             int startPos, endPos;
   1188             selectionStartEnd(startPos, endPos);
   1189             if (selectionState() == SelectionStart) {
   1190                 endPos = textLength();
   1191 
   1192                 // to handle selection from end of text to end of line
   1193                 if (startPos && startPos == endPos)
   1194                     startPos = endPos - 1;
   1195             } else if (selectionState() == SelectionEnd)
   1196                 startPos = 0;
   1197 
   1198             for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
   1199                 if (box->isSelected(startPos, endPos)) {
   1200                     box->root().setHasSelectedChildren(true);
   1201                 }
   1202             }
   1203         } else {
   1204             for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
   1205                 box->root().setHasSelectedChildren(state == SelectionInside);
   1206             }
   1207         }
   1208     }
   1209 
   1210     // The containing block can be null in case of an orphaned tree.
   1211     RenderBlock* containingBlock = this->containingBlock();
   1212     if (containingBlock && !containingBlock->isRenderView())
   1213         containingBlock->setSelectionState(state);
   1214 }
   1215 
   1216 void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force)
   1217 {
   1218     if (!force && equal(m_text.impl(), text.get()))
   1219         return;
   1220 
   1221     unsigned oldLen = textLength();
   1222     unsigned newLen = text->length();
   1223     int delta = newLen - oldLen;
   1224     unsigned end = len ? offset + len - 1 : offset;
   1225 
   1226     RootInlineBox* firstRootBox = 0;
   1227     RootInlineBox* lastRootBox = 0;
   1228 
   1229     bool dirtiedLines = false;
   1230 
   1231     // Dirty all text boxes that include characters in between offset and offset+len.
   1232     for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
   1233         // FIXME: This shouldn't rely on the end of a dirty line box. See https://bugs.webkit.org/show_bug.cgi?id=97264
   1234         // Text run is entirely before the affected range.
   1235         if (curr->end() < offset)
   1236             continue;
   1237 
   1238         // Text run is entirely after the affected range.
   1239         if (curr->start() > end) {
   1240             curr->offsetRun(delta);
   1241             RootInlineBox* root = &curr->root();
   1242             if (!firstRootBox) {
   1243                 firstRootBox = root;
   1244                 // The affected area was in between two runs. Go ahead and mark the root box of
   1245                 // the run after the affected area as dirty.
   1246                 firstRootBox->markDirty();
   1247                 dirtiedLines = true;
   1248             }
   1249             lastRootBox = root;
   1250         } else if (curr->end() >= offset && curr->end() <= end) {
   1251             // Text run overlaps with the left end of the affected range.
   1252             curr->dirtyLineBoxes();
   1253             dirtiedLines = true;
   1254         } else if (curr->start() <= offset && curr->end() >= end) {
   1255             // Text run subsumes the affected range.
   1256             curr->dirtyLineBoxes();
   1257             dirtiedLines = true;
   1258         } else if (curr->start() <= end && curr->end() >= end) {
   1259             // Text run overlaps with right end of the affected range.
   1260             curr->dirtyLineBoxes();
   1261             dirtiedLines = true;
   1262         }
   1263     }
   1264 
   1265     // Now we have to walk all of the clean lines and adjust their cached line break information
   1266     // to reflect our updated offsets.
   1267     if (lastRootBox)
   1268         lastRootBox = lastRootBox->nextRootBox();
   1269     if (firstRootBox) {
   1270         RootInlineBox* prev = firstRootBox->prevRootBox();
   1271         if (prev)
   1272             firstRootBox = prev;
   1273     } else if (lastTextBox()) {
   1274         ASSERT(!lastRootBox);
   1275         firstRootBox = &lastTextBox()->root();
   1276         firstRootBox->markDirty();
   1277         dirtiedLines = true;
   1278     }
   1279     for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
   1280         if (curr->lineBreakObj() == this && curr->lineBreakPos() > end)
   1281             curr->setLineBreakPos(clampToInteger(curr->lineBreakPos() + delta));
   1282     }
   1283 
   1284     // If the text node is empty, dirty the line where new text will be inserted.
   1285     if (!firstTextBox() && parent()) {
   1286         parent()->dirtyLinesFromChangedChild(this);
   1287         dirtiedLines = true;
   1288     }
   1289 
   1290     m_linesDirty = dirtiedLines;
   1291     setText(text, force || dirtiedLines);
   1292 }
   1293 
   1294 void RenderText::transformText()
   1295 {
   1296     if (RefPtr<StringImpl> textToTransform = originalText())
   1297         setText(textToTransform.release(), true);
   1298 }
   1299 
   1300 static inline bool isInlineFlowOrEmptyText(const RenderObject* o)
   1301 {
   1302     if (o->isRenderInline())
   1303         return true;
   1304     if (!o->isText())
   1305         return false;
   1306     return toRenderText(o)->text().isEmpty();
   1307 }
   1308 
   1309 UChar RenderText::previousCharacter() const
   1310 {
   1311     // find previous text renderer if one exists
   1312     const RenderObject* previousText = this;
   1313     while ((previousText = previousText->previousInPreOrder()))
   1314         if (!isInlineFlowOrEmptyText(previousText))
   1315             break;
   1316     UChar prev = ' ';
   1317     if (previousText && previousText->isText())
   1318         if (StringImpl* previousString = toRenderText(previousText)->text().impl())
   1319             prev = (*previousString)[previousString->length() - 1];
   1320     return prev;
   1321 }
   1322 
   1323 void RenderText::addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
   1324 {
   1325     // Text nodes aren't event targets, so don't descend any further.
   1326 }
   1327 
   1328 void applyTextTransform(const RenderStyle* style, String& text, UChar previousCharacter)
   1329 {
   1330     if (!style)
   1331         return;
   1332 
   1333     switch (style->textTransform()) {
   1334     case TTNONE:
   1335         break;
   1336     case CAPITALIZE:
   1337         makeCapitalized(&text, previousCharacter);
   1338         break;
   1339     case UPPERCASE:
   1340         text = text.upper(style->locale());
   1341         break;
   1342     case LOWERCASE:
   1343         text = text.lower(style->locale());
   1344         break;
   1345     }
   1346 }
   1347 
   1348 void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
   1349 {
   1350     ASSERT(text);
   1351     m_text = text;
   1352 
   1353     if (style()) {
   1354         applyTextTransform(style(), m_text, previousCharacter());
   1355 
   1356         // We use the same characters here as for list markers.
   1357         // See the listMarkerText function in RenderListMarker.cpp.
   1358         switch (style()->textSecurity()) {
   1359         case TSNONE:
   1360             break;
   1361         case TSCIRCLE:
   1362             secureText(whiteBullet);
   1363             break;
   1364         case TSDISC:
   1365             secureText(bullet);
   1366             break;
   1367         case TSSQUARE:
   1368             secureText(blackSquare);
   1369         }
   1370     }
   1371 
   1372     ASSERT(m_text);
   1373     ASSERT(!isBR() || (textLength() == 1 && m_text[0] == '\n'));
   1374 
   1375     m_isAllASCII = m_text.containsOnlyASCII();
   1376     m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
   1377 }
   1378 
   1379 void RenderText::secureText(UChar mask)
   1380 {
   1381     if (!m_text.length())
   1382         return;
   1383 
   1384     int lastTypedCharacterOffsetToReveal = -1;
   1385     UChar revealedText;
   1386     SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->get(this) : 0;
   1387     if (secureTextTimer && secureTextTimer->isActive()) {
   1388         lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOffset();
   1389         if (lastTypedCharacterOffsetToReveal >= 0)
   1390             revealedText = m_text[lastTypedCharacterOffsetToReveal];
   1391     }
   1392 
   1393     m_text.fill(mask);
   1394     if (lastTypedCharacterOffsetToReveal >= 0) {
   1395         m_text.replace(lastTypedCharacterOffsetToReveal, 1, String(&revealedText, 1));
   1396         // m_text may be updated later before timer fires. We invalidate the lastTypedCharacterOffset to avoid inconsistency.
   1397         secureTextTimer->invalidate();
   1398     }
   1399 }
   1400 
   1401 void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
   1402 {
   1403     ASSERT(text);
   1404 
   1405     if (!force && equal(m_text.impl(), text.get()))
   1406         return;
   1407 
   1408     setTextInternal(text);
   1409     // If preferredLogicalWidthsDirty() of an orphan child is true, RenderObjectChildList::
   1410     // insertChildNode() fails to set true to owner. To avoid that, we call
   1411     // setNeedsLayoutAndPrefWidthsRecalc() only if this RenderText has parent.
   1412     if (parent())
   1413         setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
   1414     m_knownToHaveNoOverflowAndNoFallbackFonts = false;
   1415 
   1416     if (AXObjectCache* cache = document().existingAXObjectCache())
   1417         cache->textChanged(this);
   1418 }
   1419 
   1420 void RenderText::dirtyLineBoxes(bool fullLayout)
   1421 {
   1422     if (fullLayout)
   1423         deleteTextBoxes();
   1424     else if (!m_linesDirty) {
   1425         for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
   1426             box->dirtyLineBoxes();
   1427     }
   1428     m_linesDirty = false;
   1429 }
   1430 
   1431 InlineTextBox* RenderText::createTextBox()
   1432 {
   1433     return new InlineTextBox(*this);
   1434 }
   1435 
   1436 InlineTextBox* RenderText::createInlineTextBox()
   1437 {
   1438     InlineTextBox* textBox = createTextBox();
   1439     if (!m_firstTextBox)
   1440         m_firstTextBox = m_lastTextBox = textBox;
   1441     else {
   1442         m_lastTextBox->setNextTextBox(textBox);
   1443         textBox->setPreviousTextBox(m_lastTextBox);
   1444         m_lastTextBox = textBox;
   1445     }
   1446     textBox->setIsText(true);
   1447     return textBox;
   1448 }
   1449 
   1450 void RenderText::positionLineBox(InlineBox* box)
   1451 {
   1452     InlineTextBox* s = toInlineTextBox(box);
   1453 
   1454     // FIXME: should not be needed!!!
   1455     if (!s->len()) {
   1456         // We want the box to be destroyed.
   1457         s->remove(DontMarkLineBoxes);
   1458         if (m_firstTextBox == s)
   1459             m_firstTextBox = s->nextTextBox();
   1460         else
   1461             s->prevTextBox()->setNextTextBox(s->nextTextBox());
   1462         if (m_lastTextBox == s)
   1463             m_lastTextBox = s->prevTextBox();
   1464         else
   1465             s->nextTextBox()->setPreviousTextBox(s->prevTextBox());
   1466         s->destroy();
   1467         return;
   1468     }
   1469 
   1470     m_containsReversedText |= !s->isLeftToRightDirection();
   1471 }
   1472 
   1473 float RenderText::width(unsigned from, unsigned len, float xPos, TextDirection textDirection, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
   1474 {
   1475     if (from >= textLength())
   1476         return 0;
   1477 
   1478     if (from + len > textLength())
   1479         len = textLength() - from;
   1480 
   1481     return width(from, len, style(firstLine)->font(), xPos, textDirection, fallbackFonts, glyphOverflow);
   1482 }
   1483 
   1484 float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
   1485 {
   1486     ASSERT(from + len <= textLength());
   1487     if (!textLength())
   1488         return 0;
   1489 
   1490     float w;
   1491     if (&f == &style()->font()) {
   1492         if (!style()->preserveNewline() && !from && len == textLength() && (!glyphOverflow || !glyphOverflow->computeBounds)) {
   1493             if (fallbackFonts) {
   1494                 ASSERT(glyphOverflow);
   1495                 if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
   1496                     const_cast<RenderText*>(this)->computePreferredLogicalWidths(0, *fallbackFonts, *glyphOverflow);
   1497                     if (fallbackFonts->isEmpty() && !glyphOverflow->left && !glyphOverflow->right && !glyphOverflow->top && !glyphOverflow->bottom)
   1498                         m_knownToHaveNoOverflowAndNoFallbackFonts = true;
   1499                 }
   1500                 w = m_maxWidth;
   1501             } else {
   1502                 w = maxLogicalWidth();
   1503             }
   1504         } else {
   1505             w = widthFromCache(f, from, len, xPos, textDirection, fallbackFonts, glyphOverflow);
   1506         }
   1507     } else {
   1508         TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, from, len, style(), textDirection);
   1509         run.setCharactersLength(textLength() - from);
   1510         ASSERT(run.charactersLength() >= run.length());
   1511 
   1512         run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
   1513         run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
   1514         run.setXPos(xPos);
   1515         w = f.width(run, fallbackFonts, glyphOverflow);
   1516     }
   1517 
   1518     return w;
   1519 }
   1520 
   1521 IntRect RenderText::linesBoundingBox() const
   1522 {
   1523     IntRect result;
   1524 
   1525     ASSERT(!firstTextBox() == !lastTextBox());  // Either both are null or both exist.
   1526     if (firstTextBox() && lastTextBox()) {
   1527         // Return the width of the minimal left side and the maximal right side.
   1528         float logicalLeftSide = 0;
   1529         float logicalRightSide = 0;
   1530         for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
   1531             if (curr == firstTextBox() || curr->logicalLeft() < logicalLeftSide)
   1532                 logicalLeftSide = curr->logicalLeft();
   1533             if (curr == firstTextBox() || curr->logicalRight() > logicalRightSide)
   1534                 logicalRightSide = curr->logicalRight();
   1535         }
   1536 
   1537         bool isHorizontal = style()->isHorizontalWritingMode();
   1538 
   1539         float x = isHorizontal ? logicalLeftSide : firstTextBox()->x();
   1540         float y = isHorizontal ? firstTextBox()->y() : logicalLeftSide;
   1541         float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTextBox()->logicalBottom() - x;
   1542         float height = isHorizontal ? lastTextBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
   1543         result = enclosingIntRect(FloatRect(x, y, width, height));
   1544     }
   1545 
   1546     return result;
   1547 }
   1548 
   1549 LayoutRect RenderText::linesVisualOverflowBoundingBox() const
   1550 {
   1551     if (!firstTextBox())
   1552         return LayoutRect();
   1553 
   1554     // Return the width of the minimal left side and the maximal right side.
   1555     LayoutUnit logicalLeftSide = LayoutUnit::max();
   1556     LayoutUnit logicalRightSide = LayoutUnit::min();
   1557     for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
   1558         logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
   1559         logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
   1560     }
   1561 
   1562     LayoutUnit logicalTop = firstTextBox()->logicalTopVisualOverflow();
   1563     LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
   1564     LayoutUnit logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - logicalTop;
   1565 
   1566     LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
   1567     if (!style()->isHorizontalWritingMode())
   1568         rect = rect.transposedRect();
   1569     return rect;
   1570 }
   1571 
   1572 LayoutRect RenderText::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const
   1573 {
   1574     RenderObject* rendererToRepaint = containingBlock();
   1575 
   1576     // Do not cross self-painting layer boundaries.
   1577     RenderObject* enclosingLayerRenderer = enclosingLayer()->renderer();
   1578     if (enclosingLayerRenderer != rendererToRepaint && !rendererToRepaint->isDescendantOf(enclosingLayerRenderer))
   1579         rendererToRepaint = enclosingLayerRenderer;
   1580 
   1581     // The renderer we chose to repaint may be an ancestor of paintInvalidationContainer, but we need to do a paintInvalidationContainer-relative repaint.
   1582     if (paintInvalidationContainer && paintInvalidationContainer != rendererToRepaint && !rendererToRepaint->isDescendantOf(paintInvalidationContainer))
   1583         return paintInvalidationContainer->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer);
   1584 
   1585     return rendererToRepaint->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer);
   1586 }
   1587 
   1588 LayoutRect RenderText::selectionRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, bool clipToVisibleContent)
   1589 {
   1590     ASSERT(!needsLayout());
   1591 
   1592     if (selectionState() == SelectionNone)
   1593         return LayoutRect();
   1594     RenderBlock* cb = containingBlock();
   1595     if (!cb)
   1596         return LayoutRect();
   1597 
   1598     // Now calculate startPos and endPos for painting selection.
   1599     // We include a selection while endPos > 0
   1600     int startPos, endPos;
   1601     if (selectionState() == SelectionInside) {
   1602         // We are fully selected.
   1603         startPos = 0;
   1604         endPos = textLength();
   1605     } else {
   1606         selectionStartEnd(startPos, endPos);
   1607         if (selectionState() == SelectionStart)
   1608             endPos = textLength();
   1609         else if (selectionState() == SelectionEnd)
   1610             startPos = 0;
   1611     }
   1612 
   1613     if (startPos == endPos)
   1614         return IntRect();
   1615 
   1616     LayoutRect rect;
   1617     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
   1618         rect.unite(box->localSelectionRect(startPos, endPos));
   1619         rect.unite(ellipsisRectForBox(box, startPos, endPos));
   1620     }
   1621 
   1622     if (clipToVisibleContent)
   1623         mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect);
   1624     else {
   1625         if (cb->hasColumns())
   1626             cb->adjustRectForColumns(rect);
   1627 
   1628         rect = localToContainerQuad(FloatRect(rect), paintInvalidationContainer).enclosingBoundingBox();
   1629     }
   1630 
   1631     return rect;
   1632 }
   1633 
   1634 int RenderText::caretMinOffset() const
   1635 {
   1636     InlineTextBox* box = firstTextBox();
   1637     if (!box)
   1638         return 0;
   1639     int minOffset = box->start();
   1640     for (box = box->nextTextBox(); box; box = box->nextTextBox())
   1641         minOffset = min<int>(minOffset, box->start());
   1642     return minOffset;
   1643 }
   1644 
   1645 int RenderText::caretMaxOffset() const
   1646 {
   1647     InlineTextBox* box = lastTextBox();
   1648     if (!lastTextBox())
   1649         return textLength();
   1650 
   1651     int maxOffset = box->start() + box->len();
   1652     for (box = box->prevTextBox(); box; box = box->prevTextBox())
   1653         maxOffset = max<int>(maxOffset, box->start() + box->len());
   1654     return maxOffset;
   1655 }
   1656 
   1657 unsigned RenderText::renderedTextLength() const
   1658 {
   1659     int l = 0;
   1660     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
   1661         l += box->len();
   1662     return l;
   1663 }
   1664 
   1665 int RenderText::previousOffset(int current) const
   1666 {
   1667     if (isAllASCII() || m_text.is8Bit())
   1668         return current - 1;
   1669 
   1670     StringImpl* textImpl = m_text.impl();
   1671     TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
   1672     if (!iterator)
   1673         return current - 1;
   1674 
   1675     long result = iterator->preceding(current);
   1676     if (result == TextBreakDone)
   1677         result = current - 1;
   1678 
   1679 
   1680     return result;
   1681 }
   1682 
   1683 #if OS(POSIX)
   1684 
   1685 #define HANGUL_CHOSEONG_START (0x1100)
   1686 #define HANGUL_CHOSEONG_END (0x115F)
   1687 #define HANGUL_JUNGSEONG_START (0x1160)
   1688 #define HANGUL_JUNGSEONG_END (0x11A2)
   1689 #define HANGUL_JONGSEONG_START (0x11A8)
   1690 #define HANGUL_JONGSEONG_END (0x11F9)
   1691 #define HANGUL_SYLLABLE_START (0xAC00)
   1692 #define HANGUL_SYLLABLE_END (0xD7AF)
   1693 #define HANGUL_JONGSEONG_COUNT (28)
   1694 
   1695 enum HangulState {
   1696     HangulStateL,
   1697     HangulStateV,
   1698     HangulStateT,
   1699     HangulStateLV,
   1700     HangulStateLVT,
   1701     HangulStateBreak
   1702 };
   1703 
   1704 inline bool isHangulLVT(UChar32 character)
   1705 {
   1706     return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
   1707 }
   1708 
   1709 inline bool isMark(UChar32 c)
   1710 {
   1711     int8_t charType = u_charType(c);
   1712     return charType == U_NON_SPACING_MARK || charType == U_ENCLOSING_MARK || charType == U_COMBINING_SPACING_MARK;
   1713 }
   1714 
   1715 inline bool isRegionalIndicator(UChar32 c)
   1716 {
   1717     // National flag emoji each consists of a pair of regional indicator symbols.
   1718     return 0x1F1E6 <= c && c <= 0x1F1FF;
   1719 }
   1720 
   1721 #endif
   1722 
   1723 int RenderText::previousOffsetForBackwardDeletion(int current) const
   1724 {
   1725 #if OS(POSIX)
   1726     ASSERT(m_text);
   1727     StringImpl& text = *m_text.impl();
   1728     UChar32 character;
   1729     bool sawRegionalIndicator = false;
   1730     while (current > 0) {
   1731         if (U16_IS_TRAIL(text[--current]))
   1732             --current;
   1733         if (current < 0)
   1734             break;
   1735 
   1736         UChar32 character = text.characterStartingAt(current);
   1737 
   1738         if (sawRegionalIndicator) {
   1739             // We don't check if the pair of regional indicator symbols before current position can actually be combined
   1740             // into a flag, and just delete it. This may not agree with how the pair is rendered in edge cases,
   1741             // but is good enough in practice.
   1742             if (isRegionalIndicator(character))
   1743                 break;
   1744             // Don't delete a preceding character that isn't a regional indicator symbol.
   1745             U16_FWD_1_UNSAFE(text, current);
   1746         }
   1747 
   1748         // We don't combine characters in Armenian ... Limbu range for backward deletion.
   1749         if ((character >= 0x0530) && (character < 0x1950))
   1750             break;
   1751 
   1752         if (isRegionalIndicator(character)) {
   1753             sawRegionalIndicator = true;
   1754             continue;
   1755         }
   1756 
   1757         if (!isMark(character) && (character != 0xFF9E) && (character != 0xFF9F))
   1758             break;
   1759     }
   1760 
   1761     if (current <= 0)
   1762         return current;
   1763 
   1764     // Hangul
   1765     character = text.characterStartingAt(current);
   1766     if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) {
   1767         HangulState state;
   1768 
   1769         if (character < HANGUL_JUNGSEONG_START)
   1770             state = HangulStateL;
   1771         else if (character < HANGUL_JONGSEONG_START)
   1772             state = HangulStateV;
   1773         else if (character < HANGUL_SYLLABLE_START)
   1774             state = HangulStateT;
   1775         else
   1776             state = isHangulLVT(character) ? HangulStateLVT : HangulStateLV;
   1777 
   1778         while (current > 0 && ((character = text.characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) {
   1779             switch (state) {
   1780             case HangulStateV:
   1781                 if (character <= HANGUL_CHOSEONG_END)
   1782                     state = HangulStateL;
   1783                 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END) && !isHangulLVT(character))
   1784                     state = HangulStateLV;
   1785                 else if (character > HANGUL_JUNGSEONG_END)
   1786                     state = HangulStateBreak;
   1787                 break;
   1788             case HangulStateT:
   1789                 if ((character >= HANGUL_JUNGSEONG_START) && (character <= HANGUL_JUNGSEONG_END))
   1790                     state = HangulStateV;
   1791                 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))
   1792                     state = (isHangulLVT(character) ? HangulStateLVT : HangulStateLV);
   1793                 else if (character < HANGUL_JUNGSEONG_START)
   1794                     state = HangulStateBreak;
   1795                 break;
   1796             default:
   1797                 state = (character < HANGUL_JUNGSEONG_START) ? HangulStateL : HangulStateBreak;
   1798                 break;
   1799             }
   1800             if (state == HangulStateBreak)
   1801                 break;
   1802 
   1803             --current;
   1804         }
   1805     }
   1806 
   1807     return current;
   1808 #else
   1809     // Platforms other than Unix-like delete by one code point.
   1810     if (U16_IS_TRAIL(m_text[--current]))
   1811         --current;
   1812     if (current < 0)
   1813         current = 0;
   1814     return current;
   1815 #endif
   1816 }
   1817 
   1818 int RenderText::nextOffset(int current) const
   1819 {
   1820     if (isAllASCII() || m_text.is8Bit())
   1821         return current + 1;
   1822 
   1823     StringImpl* textImpl = m_text.impl();
   1824     TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
   1825     if (!iterator)
   1826         return current + 1;
   1827 
   1828     long result = iterator->following(current);
   1829     if (result == TextBreakDone)
   1830         result = current + 1;
   1831 
   1832     return result;
   1833 }
   1834 
   1835 bool RenderText::computeCanUseSimpleFontCodePath() const
   1836 {
   1837     if (isAllASCII() || m_text.is8Bit())
   1838         return true;
   1839     return Character::characterRangeCodePath(characters16(), length()) == SimplePath;
   1840 }
   1841 
   1842 #ifndef NDEBUG
   1843 
   1844 void RenderText::checkConsistency() const
   1845 {
   1846 #ifdef CHECK_CONSISTENCY
   1847     const InlineTextBox* prev = 0;
   1848     for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) {
   1849         ASSERT(child->renderer() == this);
   1850         ASSERT(child->prevTextBox() == prev);
   1851         prev = child;
   1852     }
   1853     ASSERT(prev == m_lastTextBox);
   1854 #endif
   1855 }
   1856 
   1857 #endif
   1858 
   1859 void RenderText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset)
   1860 {
   1861     if (!gSecureTextTimers)
   1862         gSecureTextTimers = new SecureTextTimerMap;
   1863 
   1864     SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this);
   1865     if (!secureTextTimer) {
   1866         secureTextTimer = new SecureTextTimer(this);
   1867         gSecureTextTimers->add(this, secureTextTimer);
   1868     }
   1869     secureTextTimer->restartWithNewText(lastTypedCharacterOffset);
   1870 }
   1871 
   1872 PassRefPtr<AbstractInlineTextBox> RenderText::firstAbstractInlineTextBox()
   1873 {
   1874     return AbstractInlineTextBox::getOrCreate(this, m_firstTextBox);
   1875 }
   1876 
   1877 } // namespace WebCore
   1878