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/TextRunConstructor.h"
     42 #include "core/rendering/break_lines.h"
     43 #include "platform/fonts/Character.h"
     44 #include "platform/fonts/FontCache.h"
     45 #include "platform/geometry/FloatQuad.h"
     46 #include "platform/text/BidiResolver.h"
     47 #include "platform/text/TextBreakIterator.h"
     48 #include "platform/text/TextRunIterator.h"
     49 #include "wtf/text/StringBuffer.h"
     50 #include "wtf/text/StringBuilder.h"
     51 #include "wtf/unicode/CharacterNames.h"
     52 
     53 using namespace WTF;
     54 using namespace Unicode;
     55 
     56 namespace blink {
     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 >= std::numeric_limits<unsigned>::max())
    108         CRASH();
    109 
    110     StringBuffer<UChar> stringWithPrevious(length + 1);
    111     stringWithPrevious[0] = previous == noBreakSpace ? space : 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] = space;
    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 #if ENABLE(ASSERT)
    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 paint invalidations 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         setNeedsLayoutAndPrefWidthsRecalc();
    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 blink::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(space);
    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 = std::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 = std::min(start, static_cast<unsigned>(INT_MAX));
    363     end = std::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 = std::max<int>(startPos - box->start(), 0);
    401         int ellipsisEndPosition = std::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 = std::min(start, static_cast<unsigned>(INT_MAX));
    446     end = std::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 = std::min(rootBox.selectionTop(), rootBox.lineTop());
    615         if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirection == top)) {
    616             LayoutUnit bottom = rootBox.selectionBottom();
    617             if (rootBox.nextRootBox())
    618                 bottom = std::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 = std::min<float>(0, rootLeft);
    675     rightEdge = std::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     // for dir=auto, use inlineBoxBidiLevel() to test the correct direction for the cursor.
    698     if (rightAligned && (node() && node()->selfOrAncestorHasDirAutoAttribute())) {
    699         if (inlineBox->bidiLevel()%2 != 1)
    700             rightAligned = false;
    701     }
    702 
    703     if (rightAligned) {
    704         left = std::max(left, leftEdge);
    705         left = std::min(left, rootRight - caretWidth);
    706     } else {
    707         left = std::min(left, rightEdge - caretWidthRightOfOffset);
    708         left = std::max(left, rootLeft);
    709     }
    710 
    711     return style()->isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth);
    712 }
    713 
    714 ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
    715 {
    716     if (style()->hasTextCombine() && isCombineText()) {
    717         const RenderCombineText* combineText = toRenderCombineText(this);
    718         if (combineText->isCombined())
    719             return combineText->combinedTextWidth(f);
    720     }
    721 
    722     if (f.isFixedPitch() && f.fontDescription().variant() == FontVariantNormal && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
    723         float monospaceCharacterWidth = f.spaceWidth();
    724         float w = 0;
    725         bool isSpace;
    726         ASSERT(m_text);
    727         StringImpl& text = *m_text.impl();
    728         for (int i = start; i < start + len; i++) {
    729             char c = text[i];
    730             if (c <= space) {
    731                 if (c == space || c == newlineCharacter) {
    732                     w += monospaceCharacterWidth;
    733                     isSpace = true;
    734                 } else if (c == characterTabulation) {
    735                     if (style()->collapseWhiteSpace()) {
    736                         w += monospaceCharacterWidth;
    737                         isSpace = true;
    738                     } else {
    739                         w += f.tabWidth(style()->tabSize(), xPos + w);
    740                         isSpace = false;
    741                     }
    742                 } else
    743                     isSpace = false;
    744             } else {
    745                 w += monospaceCharacterWidth;
    746                 isSpace = false;
    747             }
    748             if (isSpace && i > start)
    749                 w += f.fontDescription().wordSpacing();
    750         }
    751         return w;
    752     }
    753 
    754     TextRun run = constructTextRun(const_cast<RenderText*>(this), f, this, start, len, style(), textDirection);
    755     run.setCharactersLength(textLength() - start);
    756     ASSERT(run.charactersLength() >= run.length());
    757 
    758     run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
    759     run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
    760     run.setXPos(xPos);
    761     FontCachePurgePreventer fontCachePurgePreventer;
    762     return f.width(run, fallbackFonts, glyphOverflow);
    763 }
    764 
    765 void RenderText::trimmedPrefWidths(float leadWidth,
    766     float& firstLineMinWidth, bool& hasBreakableStart,
    767     float& lastLineMinWidth, bool& hasBreakableEnd,
    768     bool& hasBreakableChar, bool& hasBreak,
    769     float& firstLineMaxWidth, float& lastLineMaxWidth,
    770     float& minWidth, float& maxWidth, bool& stripFrontSpaces,
    771     TextDirection direction)
    772 {
    773     bool collapseWhiteSpace = style()->collapseWhiteSpace();
    774     if (!collapseWhiteSpace)
    775         stripFrontSpaces = false;
    776 
    777     if (m_hasTab || preferredLogicalWidthsDirty())
    778         computePreferredLogicalWidths(leadWidth);
    779 
    780     hasBreakableStart = !stripFrontSpaces && m_hasBreakableStart;
    781     hasBreakableEnd = m_hasBreakableEnd;
    782 
    783     int len = textLength();
    784 
    785     if (!len || (stripFrontSpaces && text().impl()->containsOnlyWhitespace())) {
    786         firstLineMinWidth = 0;
    787         lastLineMinWidth = 0;
    788         firstLineMaxWidth = 0;
    789         lastLineMaxWidth = 0;
    790         minWidth = 0;
    791         maxWidth = 0;
    792         hasBreak = false;
    793         return;
    794     }
    795 
    796     minWidth = m_minWidth;
    797     maxWidth = m_maxWidth;
    798 
    799     firstLineMinWidth = m_firstLineMinWidth;
    800     lastLineMinWidth = m_lastLineLineMinWidth;
    801 
    802     hasBreakableChar = m_hasBreakableChar;
    803     hasBreak = m_hasBreak;
    804 
    805     ASSERT(m_text);
    806     StringImpl& text = *m_text.impl();
    807     if (text[0] == space || (text[0] == newlineCharacter && !style()->preserveNewline()) || text[0] == characterTabulation) {
    808         const Font& font = style()->font(); // FIXME: This ignores first-line.
    809         if (stripFrontSpaces) {
    810             const UChar spaceChar = space;
    811             float spaceWidth = font.width(constructTextRun(this, font, &spaceChar, 1, style(), direction));
    812             maxWidth -= spaceWidth;
    813         } else {
    814             maxWidth += font.fontDescription().wordSpacing();
    815         }
    816     }
    817 
    818     stripFrontSpaces = collapseWhiteSpace && m_hasEndWhiteSpace;
    819 
    820     if (!style()->autoWrap() || minWidth > maxWidth)
    821         minWidth = maxWidth;
    822 
    823     // Compute our max widths by scanning the string for newlines.
    824     if (hasBreak) {
    825         const Font& f = style()->font(); // FIXME: This ignores first-line.
    826         bool firstLine = true;
    827         firstLineMaxWidth = maxWidth;
    828         lastLineMaxWidth = maxWidth;
    829         for (int i = 0; i < len; i++) {
    830             int linelen = 0;
    831             while (i + linelen < len && text[i + linelen] != newlineCharacter)
    832                 linelen++;
    833 
    834             if (linelen) {
    835                 lastLineMaxWidth = widthFromCache(f, i, linelen, leadWidth + lastLineMaxWidth, direction, 0, 0);
    836                 if (firstLine) {
    837                     firstLine = false;
    838                     leadWidth = 0;
    839                     firstLineMaxWidth = lastLineMaxWidth;
    840                 }
    841                 i += linelen;
    842             } else if (firstLine) {
    843                 firstLineMaxWidth = 0;
    844                 firstLine = false;
    845                 leadWidth = 0;
    846             }
    847 
    848             if (i == len - 1) {
    849                 // A <pre> run that ends with a newline, as in, e.g.,
    850                 // <pre>Some text\n\n<span>More text</pre>
    851                 lastLineMaxWidth = 0;
    852             }
    853         }
    854     }
    855 }
    856 
    857 float RenderText::minLogicalWidth() const
    858 {
    859     if (preferredLogicalWidthsDirty())
    860         const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
    861 
    862     return m_minWidth;
    863 }
    864 
    865 float RenderText::maxLogicalWidth() const
    866 {
    867     if (preferredLogicalWidthsDirty())
    868         const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
    869 
    870     return m_maxWidth;
    871 }
    872 
    873 void RenderText::computePreferredLogicalWidths(float leadWidth)
    874 {
    875     HashSet<const SimpleFontData*> fallbackFonts;
    876     GlyphOverflow glyphOverflow;
    877     computePreferredLogicalWidths(leadWidth, fallbackFonts, glyphOverflow);
    878 
    879     // We shouldn't change our mind once we "know".
    880     ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts || (fallbackFonts.isEmpty() && glyphOverflow.isZero()));
    881     m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts.isEmpty() && glyphOverflow.isZero();
    882 }
    883 
    884 static inline float hyphenWidth(RenderText* renderer, const Font& font, TextDirection direction)
    885 {
    886     RenderStyle* style = renderer->style();
    887     return font.width(constructTextRun(renderer, font, style->hyphenString().string(), style, direction));
    888 }
    889 
    890 void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
    891 {
    892     ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts);
    893 
    894     m_minWidth = 0;
    895     m_maxWidth = 0;
    896     m_firstLineMinWidth = 0;
    897     m_lastLineLineMinWidth = 0;
    898 
    899     if (isBR())
    900         return;
    901 
    902     float currMinWidth = 0;
    903     float currMaxWidth = 0;
    904     m_hasBreakableChar = false;
    905     m_hasBreak = false;
    906     m_hasTab = false;
    907     m_hasBreakableStart = false;
    908     m_hasBreakableEnd = false;
    909     m_hasEndWhiteSpace = false;
    910 
    911     RenderStyle* styleToUse = style();
    912     const Font& f = styleToUse->font(); // FIXME: This ignores first-line.
    913     float wordSpacing = styleToUse->wordSpacing();
    914     int len = textLength();
    915     LazyLineBreakIterator breakIterator(m_text, styleToUse->locale());
    916     bool needsWordSpacing = false;
    917     bool ignoringSpaces = false;
    918     bool isSpace = false;
    919     bool firstWord = true;
    920     bool firstLine = true;
    921     int nextBreakable = -1;
    922     int lastWordBoundary = 0;
    923     float cachedWordTrailingSpaceWidth[2] = { 0, 0 }; // LTR, RTL
    924 
    925     int firstGlyphLeftOverflow = -1;
    926 
    927     bool breakAll = (styleToUse->wordBreak() == BreakAllWordBreak || styleToUse->wordBreak() == BreakWordBreak) && styleToUse->autoWrap();
    928 
    929     TextRun textRun(text());
    930     BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    931     BidiCharacterRun* run;
    932     TextDirection textDirection = styleToUse->direction();
    933     if (isOverride(styleToUse->unicodeBidi())) {
    934         run = 0;
    935     } else {
    936         BidiStatus status(textDirection, false);
    937         bidiResolver.setStatus(status);
    938         bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&textRun, 0));
    939         bool hardLineBreak = false;
    940         bool reorderRuns = false;
    941         bidiResolver.createBidiRunsForLine(TextRunIterator(&textRun, textRun.length()), NoVisualOverride, hardLineBreak, reorderRuns);
    942         BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
    943         run = bidiRuns.firstRun();
    944     }
    945 
    946     for (int i = 0; i < len; i++) {
    947         UChar c = uncheckedCharacterAt(i);
    948 
    949         if (run) {
    950             // Treat adjacent runs with the same resolved directionality
    951             // (TextDirection as opposed to WTF::Unicode::Direction) as belonging
    952             // to the same run to avoid breaking unnecessarily.
    953             while (i >= run->stop() || (run->next() && run->next()->direction() == run->direction()))
    954                 run = run->next();
    955 
    956             ASSERT(run);
    957             ASSERT(i <= run->stop());
    958             textDirection = run->direction();
    959         }
    960 
    961         bool previousCharacterIsSpace = isSpace;
    962         bool isNewline = false;
    963         if (c == newlineCharacter) {
    964             if (styleToUse->preserveNewline()) {
    965                 m_hasBreak = true;
    966                 isNewline = true;
    967                 isSpace = false;
    968             } else
    969                 isSpace = true;
    970         } else if (c == characterTabulation) {
    971             if (!styleToUse->collapseWhiteSpace()) {
    972                 m_hasTab = true;
    973                 isSpace = false;
    974             } else
    975                 isSpace = true;
    976         } else {
    977             isSpace = c == space;
    978         }
    979 
    980         bool isBreakableLocation = isNewline || (isSpace && styleToUse->autoWrap());
    981         if (!i)
    982             m_hasBreakableStart = isBreakableLocation;
    983         if (i == len - 1) {
    984             m_hasBreakableEnd = isBreakableLocation;
    985             m_hasEndWhiteSpace = isNewline || isSpace;
    986         }
    987 
    988         if (!ignoringSpaces && styleToUse->collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
    989             ignoringSpaces = true;
    990 
    991         if (ignoringSpaces && !isSpace)
    992             ignoringSpaces = false;
    993 
    994         // Ignore spaces and soft hyphens
    995         if (ignoringSpaces) {
    996             ASSERT(lastWordBoundary == i);
    997             lastWordBoundary++;
    998             continue;
    999         } else if (c == softHyphen) {
   1000             currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
   1001             if (firstGlyphLeftOverflow < 0)
   1002                 firstGlyphLeftOverflow = glyphOverflow.left;
   1003             lastWordBoundary = i + 1;
   1004             continue;
   1005         }
   1006 
   1007         bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable);
   1008         bool betweenWords = true;
   1009         int j = i;
   1010         while (c != newlineCharacter && c != space && c != characterTabulation && (c != softHyphen)) {
   1011             j++;
   1012             if (j == len)
   1013                 break;
   1014             c = uncheckedCharacterAt(j);
   1015             if (isBreakable(breakIterator, j, nextBreakable) && characterAt(j - 1) != softHyphen)
   1016                 break;
   1017             if (breakAll) {
   1018                 betweenWords = false;
   1019                 break;
   1020             }
   1021         }
   1022 
   1023         // Terminate word boundary at bidi run boundary.
   1024         if (run)
   1025             j = std::min(j, run->stop() + 1);
   1026         int wordLen = j - i;
   1027         if (wordLen) {
   1028             bool isSpace = (j < len) && c == space;
   1029 
   1030             // Non-zero only when kerning is enabled, in which case we measure words with their trailing
   1031             // space, then subtract its width.
   1032             float wordTrailingSpaceWidth = 0;
   1033             if (isSpace && (f.fontDescription().typesettingFeatures() & Kerning)) {
   1034                 ASSERT(textDirection >=0 && textDirection <= 1);
   1035                 if (!cachedWordTrailingSpaceWidth[textDirection])
   1036                     cachedWordTrailingSpaceWidth[textDirection] = f.width(constructTextRun(this, f, &space, 1, styleToUse, textDirection)) + wordSpacing;
   1037                 wordTrailingSpaceWidth = cachedWordTrailingSpaceWidth[textDirection];
   1038             }
   1039 
   1040             float w;
   1041             if (wordTrailingSpaceWidth && isSpace)
   1042                 w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth;
   1043             else {
   1044                 w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
   1045                 if (c == softHyphen)
   1046                     currMinWidth += hyphenWidth(this, f, textDirection);
   1047             }
   1048 
   1049             if (firstGlyphLeftOverflow < 0)
   1050                 firstGlyphLeftOverflow = glyphOverflow.left;
   1051             currMinWidth += w;
   1052             if (betweenWords) {
   1053                 if (lastWordBoundary == i)
   1054                     currMaxWidth += w;
   1055                 else
   1056                     currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
   1057                 lastWordBoundary = j;
   1058             }
   1059 
   1060             bool isCollapsibleWhiteSpace = (j < len) && styleToUse->isCollapsibleWhiteSpace(c);
   1061             if (j < len && styleToUse->autoWrap())
   1062                 m_hasBreakableChar = true;
   1063 
   1064             // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
   1065             // last word in the run.
   1066             if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
   1067                 currMaxWidth += wordSpacing;
   1068 
   1069             if (firstWord) {
   1070                 firstWord = false;
   1071                 // If the first character in the run is breakable, then we consider ourselves to have a beginning
   1072                 // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
   1073                 // being appended to a previous text run when considering the total minimum width of the containing block.
   1074                 if (hasBreak)
   1075                     m_hasBreakableChar = true;
   1076                 m_firstLineMinWidth = hasBreak ? 0 : currMinWidth;
   1077             }
   1078             m_lastLineLineMinWidth = currMinWidth;
   1079 
   1080             if (currMinWidth > m_minWidth)
   1081                 m_minWidth = currMinWidth;
   1082             currMinWidth = 0;
   1083 
   1084             i += wordLen - 1;
   1085         } else {
   1086             // Nowrap can never be broken, so don't bother setting the
   1087             // breakable character boolean. Pre can only be broken if we encounter a newline.
   1088             if (style()->autoWrap() || isNewline)
   1089                 m_hasBreakableChar = true;
   1090 
   1091             if (currMinWidth > m_minWidth)
   1092                 m_minWidth = currMinWidth;
   1093             currMinWidth = 0;
   1094 
   1095             if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
   1096                 if (firstLine) {
   1097                     firstLine = false;
   1098                     leadWidth = 0;
   1099                     if (!styleToUse->autoWrap())
   1100                         m_firstLineMinWidth = currMaxWidth;
   1101                 }
   1102 
   1103                 if (currMaxWidth > m_maxWidth)
   1104                     m_maxWidth = currMaxWidth;
   1105                 currMaxWidth = 0;
   1106             } else {
   1107                 TextRun run = constructTextRun(this, f, this, i, 1, styleToUse, textDirection);
   1108                 run.setCharactersLength(len - i);
   1109                 run.setUseComplexCodePath(!canUseSimpleFontCodePath());
   1110                 ASSERT(run.charactersLength() >= run.length());
   1111                 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
   1112                 run.setXPos(leadWidth + currMaxWidth);
   1113 
   1114                 currMaxWidth += f.width(run);
   1115                 glyphOverflow.right = 0;
   1116                 needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
   1117             }
   1118             ASSERT(lastWordBoundary == i);
   1119             lastWordBoundary++;
   1120         }
   1121     }
   1122     if (run)
   1123         bidiResolver.runs().deleteRuns();
   1124 
   1125     if (firstGlyphLeftOverflow > 0)
   1126         glyphOverflow.left = firstGlyphLeftOverflow;
   1127 
   1128     if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord))
   1129         currMaxWidth += wordSpacing;
   1130 
   1131     m_minWidth = std::max(currMinWidth, m_minWidth);
   1132     m_maxWidth = std::max(currMaxWidth, m_maxWidth);
   1133 
   1134     if (!styleToUse->autoWrap())
   1135         m_minWidth = m_maxWidth;
   1136 
   1137     if (styleToUse->whiteSpace() == PRE) {
   1138         if (firstLine)
   1139             m_firstLineMinWidth = m_maxWidth;
   1140         m_lastLineLineMinWidth = currMaxWidth;
   1141     }
   1142 
   1143     clearPreferredLogicalWidthsDirty();
   1144 }
   1145 
   1146 bool RenderText::isAllCollapsibleWhitespace() const
   1147 {
   1148     unsigned length = textLength();
   1149     if (is8Bit()) {
   1150         for (unsigned i = 0; i < length; ++i) {
   1151             if (!style()->isCollapsibleWhiteSpace(characters8()[i]))
   1152                 return false;
   1153         }
   1154         return true;
   1155     }
   1156     for (unsigned i = 0; i < length; ++i) {
   1157         if (!style()->isCollapsibleWhiteSpace(characters16()[i]))
   1158             return false;
   1159     }
   1160     return true;
   1161 }
   1162 
   1163 bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
   1164 {
   1165     ASSERT(m_text);
   1166     StringImpl& text = *m_text.impl();
   1167     unsigned currPos;
   1168     for (currPos = from;
   1169     currPos < from + len && (text[currPos] == newlineCharacter || text[currPos] == space || text[currPos] == characterTabulation);
   1170     currPos++) { }
   1171     return currPos >= (from + len);
   1172 }
   1173 
   1174 FloatPoint RenderText::firstRunOrigin() const
   1175 {
   1176     return IntPoint(firstRunX(), firstRunY());
   1177 }
   1178 
   1179 float RenderText::firstRunX() const
   1180 {
   1181     return m_firstTextBox ? m_firstTextBox->x() : 0;
   1182 }
   1183 
   1184 float RenderText::firstRunY() const
   1185 {
   1186     return m_firstTextBox ? m_firstTextBox->y() : 0;
   1187 }
   1188 
   1189 void RenderText::setSelectionState(SelectionState state)
   1190 {
   1191     RenderObject::setSelectionState(state);
   1192 
   1193     if (canUpdateSelectionOnRootLineBoxes()) {
   1194         if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) {
   1195             int startPos, endPos;
   1196             selectionStartEnd(startPos, endPos);
   1197             if (selectionState() == SelectionStart) {
   1198                 endPos = textLength();
   1199 
   1200                 // to handle selection from end of text to end of line
   1201                 if (startPos && startPos == endPos)
   1202                     startPos = endPos - 1;
   1203             } else if (selectionState() == SelectionEnd)
   1204                 startPos = 0;
   1205 
   1206             for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
   1207                 if (box->isSelected(startPos, endPos)) {
   1208                     box->root().setHasSelectedChildren(true);
   1209                 }
   1210             }
   1211         } else {
   1212             for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
   1213                 box->root().setHasSelectedChildren(state == SelectionInside);
   1214             }
   1215         }
   1216     }
   1217 
   1218     // The containing block can be null in case of an orphaned tree.
   1219     RenderBlock* containingBlock = this->containingBlock();
   1220     if (containingBlock && !containingBlock->isRenderView())
   1221         containingBlock->setSelectionState(state);
   1222 }
   1223 
   1224 void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force)
   1225 {
   1226     if (!force && equal(m_text.impl(), text.get()))
   1227         return;
   1228 
   1229     unsigned oldLen = textLength();
   1230     unsigned newLen = text->length();
   1231     int delta = newLen - oldLen;
   1232     unsigned end = len ? offset + len - 1 : offset;
   1233 
   1234     RootInlineBox* firstRootBox = 0;
   1235     RootInlineBox* lastRootBox = 0;
   1236 
   1237     bool dirtiedLines = false;
   1238 
   1239     // Dirty all text boxes that include characters in between offset and offset+len.
   1240     for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
   1241         // FIXME: This shouldn't rely on the end of a dirty line box. See https://bugs.webkit.org/show_bug.cgi?id=97264
   1242         // Text run is entirely before the affected range.
   1243         if (curr->end() < offset)
   1244             continue;
   1245 
   1246         // Text run is entirely after the affected range.
   1247         if (curr->start() > end) {
   1248             curr->offsetRun(delta);
   1249             RootInlineBox* root = &curr->root();
   1250             if (!firstRootBox) {
   1251                 firstRootBox = root;
   1252                 // The affected area was in between two runs. Go ahead and mark the root box of
   1253                 // the run after the affected area as dirty.
   1254                 firstRootBox->markDirty();
   1255                 dirtiedLines = true;
   1256             }
   1257             lastRootBox = root;
   1258         } else if (curr->end() >= offset && curr->end() <= end) {
   1259             // Text run overlaps with the left end of the affected range.
   1260             curr->dirtyLineBoxes();
   1261             dirtiedLines = true;
   1262         } else if (curr->start() <= offset && curr->end() >= end) {
   1263             // Text run subsumes the affected range.
   1264             curr->dirtyLineBoxes();
   1265             dirtiedLines = true;
   1266         } else if (curr->start() <= end && curr->end() >= end) {
   1267             // Text run overlaps with right end of the affected range.
   1268             curr->dirtyLineBoxes();
   1269             dirtiedLines = true;
   1270         }
   1271     }
   1272 
   1273     // Now we have to walk all of the clean lines and adjust their cached line break information
   1274     // to reflect our updated offsets.
   1275     if (lastRootBox)
   1276         lastRootBox = lastRootBox->nextRootBox();
   1277     if (firstRootBox) {
   1278         RootInlineBox* prev = firstRootBox->prevRootBox();
   1279         if (prev)
   1280             firstRootBox = prev;
   1281     } else if (lastTextBox()) {
   1282         ASSERT(!lastRootBox);
   1283         firstRootBox = &lastTextBox()->root();
   1284         firstRootBox->markDirty();
   1285         dirtiedLines = true;
   1286     }
   1287     for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
   1288         if (curr->lineBreakObj() == this && curr->lineBreakPos() > end)
   1289             curr->setLineBreakPos(clampToInteger(curr->lineBreakPos() + delta));
   1290     }
   1291 
   1292     // If the text node is empty, dirty the line where new text will be inserted.
   1293     if (!firstTextBox() && parent()) {
   1294         parent()->dirtyLinesFromChangedChild(this);
   1295         dirtiedLines = true;
   1296     }
   1297 
   1298     m_linesDirty = dirtiedLines;
   1299     setText(text, force || dirtiedLines);
   1300 }
   1301 
   1302 void RenderText::transformText()
   1303 {
   1304     if (RefPtr<StringImpl> textToTransform = originalText())
   1305         setText(textToTransform.release(), true);
   1306 }
   1307 
   1308 static inline bool isInlineFlowOrEmptyText(const RenderObject* o)
   1309 {
   1310     if (o->isRenderInline())
   1311         return true;
   1312     if (!o->isText())
   1313         return false;
   1314     return toRenderText(o)->text().isEmpty();
   1315 }
   1316 
   1317 UChar RenderText::previousCharacter() const
   1318 {
   1319     // find previous text renderer if one exists
   1320     const RenderObject* previousText = previousInPreOrder();
   1321     for (; previousText; previousText = previousText->previousInPreOrder())
   1322         if (!isInlineFlowOrEmptyText(previousText))
   1323             break;
   1324     UChar prev = space;
   1325     if (previousText && previousText->isText())
   1326         if (StringImpl* previousString = toRenderText(previousText)->text().impl())
   1327             prev = (*previousString)[previousString->length() - 1];
   1328     return prev;
   1329 }
   1330 
   1331 void RenderText::addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
   1332 {
   1333     // Text nodes aren't event targets, so don't descend any further.
   1334 }
   1335 
   1336 void applyTextTransform(const RenderStyle* style, String& text, UChar previousCharacter)
   1337 {
   1338     if (!style)
   1339         return;
   1340 
   1341     switch (style->textTransform()) {
   1342     case TTNONE:
   1343         break;
   1344     case CAPITALIZE:
   1345         makeCapitalized(&text, previousCharacter);
   1346         break;
   1347     case UPPERCASE:
   1348         text = text.upper(style->locale());
   1349         break;
   1350     case LOWERCASE:
   1351         text = text.lower(style->locale());
   1352         break;
   1353     }
   1354 }
   1355 
   1356 void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
   1357 {
   1358     ASSERT(text);
   1359     m_text = text;
   1360 
   1361     if (style()) {
   1362         applyTextTransform(style(), m_text, previousCharacter());
   1363 
   1364         // We use the same characters here as for list markers.
   1365         // See the listMarkerText function in RenderListMarker.cpp.
   1366         switch (style()->textSecurity()) {
   1367         case TSNONE:
   1368             break;
   1369         case TSCIRCLE:
   1370             secureText(whiteBullet);
   1371             break;
   1372         case TSDISC:
   1373             secureText(bullet);
   1374             break;
   1375         case TSSQUARE:
   1376             secureText(blackSquare);
   1377         }
   1378     }
   1379 
   1380     ASSERT(m_text);
   1381     ASSERT(!isBR() || (textLength() == 1 && m_text[0] == newlineCharacter));
   1382 
   1383     m_isAllASCII = m_text.containsOnlyASCII();
   1384     m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
   1385 }
   1386 
   1387 void RenderText::secureText(UChar mask)
   1388 {
   1389     if (!m_text.length())
   1390         return;
   1391 
   1392     int lastTypedCharacterOffsetToReveal = -1;
   1393     UChar revealedText;
   1394     SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->get(this) : 0;
   1395     if (secureTextTimer && secureTextTimer->isActive()) {
   1396         lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOffset();
   1397         if (lastTypedCharacterOffsetToReveal >= 0)
   1398             revealedText = m_text[lastTypedCharacterOffsetToReveal];
   1399     }
   1400 
   1401     m_text.fill(mask);
   1402     if (lastTypedCharacterOffsetToReveal >= 0) {
   1403         m_text.replace(lastTypedCharacterOffsetToReveal, 1, String(&revealedText, 1));
   1404         // m_text may be updated later before timer fires. We invalidate the lastTypedCharacterOffset to avoid inconsistency.
   1405         secureTextTimer->invalidate();
   1406     }
   1407 }
   1408 
   1409 void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
   1410 {
   1411     ASSERT(text);
   1412 
   1413     if (!force && equal(m_text.impl(), text.get()))
   1414         return;
   1415 
   1416     setTextInternal(text);
   1417     // If preferredLogicalWidthsDirty() of an orphan child is true, RenderObjectChildList::
   1418     // insertChildNode() fails to set true to owner. To avoid that, we call
   1419     // setNeedsLayoutAndPrefWidthsRecalc() only if this RenderText has parent.
   1420     if (parent())
   1421         setNeedsLayoutAndPrefWidthsRecalc();
   1422     m_knownToHaveNoOverflowAndNoFallbackFonts = false;
   1423 
   1424     if (AXObjectCache* cache = document().existingAXObjectCache())
   1425         cache->textChanged(this);
   1426 }
   1427 
   1428 void RenderText::dirtyLineBoxes(bool fullLayout)
   1429 {
   1430     if (fullLayout)
   1431         deleteTextBoxes();
   1432     else if (!m_linesDirty) {
   1433         for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
   1434             box->dirtyLineBoxes();
   1435     }
   1436     m_linesDirty = false;
   1437 }
   1438 
   1439 InlineTextBox* RenderText::createTextBox()
   1440 {
   1441     return new InlineTextBox(*this);
   1442 }
   1443 
   1444 InlineTextBox* RenderText::createInlineTextBox()
   1445 {
   1446     InlineTextBox* textBox = createTextBox();
   1447     if (!m_firstTextBox)
   1448         m_firstTextBox = m_lastTextBox = textBox;
   1449     else {
   1450         m_lastTextBox->setNextTextBox(textBox);
   1451         textBox->setPreviousTextBox(m_lastTextBox);
   1452         m_lastTextBox = textBox;
   1453     }
   1454     textBox->setIsText(true);
   1455     return textBox;
   1456 }
   1457 
   1458 void RenderText::positionLineBox(InlineBox* box)
   1459 {
   1460     InlineTextBox* s = toInlineTextBox(box);
   1461 
   1462     // FIXME: should not be needed!!!
   1463     if (!s->len()) {
   1464         // We want the box to be destroyed.
   1465         s->remove(DontMarkLineBoxes);
   1466         if (m_firstTextBox == s)
   1467             m_firstTextBox = s->nextTextBox();
   1468         else
   1469             s->prevTextBox()->setNextTextBox(s->nextTextBox());
   1470         if (m_lastTextBox == s)
   1471             m_lastTextBox = s->prevTextBox();
   1472         else
   1473             s->nextTextBox()->setPreviousTextBox(s->prevTextBox());
   1474         s->destroy();
   1475         return;
   1476     }
   1477 
   1478     m_containsReversedText |= !s->isLeftToRightDirection();
   1479 }
   1480 
   1481 float RenderText::width(unsigned from, unsigned len, float xPos, TextDirection textDirection, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
   1482 {
   1483     if (from >= textLength())
   1484         return 0;
   1485 
   1486     if (from + len > textLength())
   1487         len = textLength() - from;
   1488 
   1489     return width(from, len, style(firstLine)->font(), xPos, textDirection, fallbackFonts, glyphOverflow);
   1490 }
   1491 
   1492 float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
   1493 {
   1494     ASSERT(from + len <= textLength());
   1495     if (!textLength())
   1496         return 0;
   1497 
   1498     float w;
   1499     if (&f == &style()->font()) {
   1500         if (!style()->preserveNewline() && !from && len == textLength() && (!glyphOverflow || !glyphOverflow->computeBounds)) {
   1501             if (fallbackFonts) {
   1502                 ASSERT(glyphOverflow);
   1503                 if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
   1504                     const_cast<RenderText*>(this)->computePreferredLogicalWidths(0, *fallbackFonts, *glyphOverflow);
   1505                     // We shouldn't change our mind once we "know".
   1506                     ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts
   1507                         || (fallbackFonts->isEmpty() && glyphOverflow->isZero()));
   1508                     m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts->isEmpty() && glyphOverflow->isZero();
   1509                 }
   1510                 w = m_maxWidth;
   1511             } else {
   1512                 w = maxLogicalWidth();
   1513             }
   1514         } else {
   1515             w = widthFromCache(f, from, len, xPos, textDirection, fallbackFonts, glyphOverflow);
   1516         }
   1517     } else {
   1518         TextRun run = constructTextRun(const_cast<RenderText*>(this), f, this, from, len, style(), textDirection);
   1519         run.setCharactersLength(textLength() - from);
   1520         ASSERT(run.charactersLength() >= run.length());
   1521 
   1522         run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
   1523         run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
   1524         run.setXPos(xPos);
   1525         w = f.width(run, fallbackFonts, glyphOverflow);
   1526     }
   1527 
   1528     return w;
   1529 }
   1530 
   1531 IntRect RenderText::linesBoundingBox() const
   1532 {
   1533     IntRect result;
   1534 
   1535     ASSERT(!firstTextBox() == !lastTextBox());  // Either both are null or both exist.
   1536     if (firstTextBox() && lastTextBox()) {
   1537         // Return the width of the minimal left side and the maximal right side.
   1538         float logicalLeftSide = 0;
   1539         float logicalRightSide = 0;
   1540         for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
   1541             if (curr == firstTextBox() || curr->logicalLeft() < logicalLeftSide)
   1542                 logicalLeftSide = curr->logicalLeft();
   1543             if (curr == firstTextBox() || curr->logicalRight() > logicalRightSide)
   1544                 logicalRightSide = curr->logicalRight();
   1545         }
   1546 
   1547         bool isHorizontal = style()->isHorizontalWritingMode();
   1548 
   1549         float x = isHorizontal ? logicalLeftSide : firstTextBox()->x();
   1550         float y = isHorizontal ? firstTextBox()->y() : logicalLeftSide;
   1551         float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTextBox()->logicalBottom() - x;
   1552         float height = isHorizontal ? lastTextBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
   1553         result = enclosingIntRect(FloatRect(x, y, width, height));
   1554     }
   1555 
   1556     return result;
   1557 }
   1558 
   1559 LayoutRect RenderText::linesVisualOverflowBoundingBox() const
   1560 {
   1561     if (!firstTextBox())
   1562         return LayoutRect();
   1563 
   1564     // Return the width of the minimal left side and the maximal right side.
   1565     LayoutUnit logicalLeftSide = LayoutUnit::max();
   1566     LayoutUnit logicalRightSide = LayoutUnit::min();
   1567     for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
   1568         LayoutRect logicalVisualOverflow = curr->logicalOverflowRect();
   1569         logicalLeftSide = std::min(logicalLeftSide, logicalVisualOverflow.x());
   1570         logicalRightSide = std::max(logicalRightSide, logicalVisualOverflow.maxX());
   1571     }
   1572 
   1573     LayoutUnit logicalTop = firstTextBox()->logicalTopVisualOverflow();
   1574     LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
   1575     LayoutUnit logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - logicalTop;
   1576 
   1577     LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
   1578     if (!style()->isHorizontalWritingMode())
   1579         rect = rect.transposedRect();
   1580     return rect;
   1581 }
   1582 
   1583 LayoutRect RenderText::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
   1584 {
   1585     // This method doesn't support paintInvalidationState, but invalidateTreeIfNeeded() never reaches RenderText.
   1586     ASSERT(!paintInvalidationState);
   1587     return parent()->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer);
   1588 }
   1589 
   1590 LayoutRect RenderText::selectionRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const
   1591 {
   1592     ASSERT(!needsLayout());
   1593 
   1594     if (selectionState() == SelectionNone)
   1595         return LayoutRect();
   1596     RenderBlock* cb = containingBlock();
   1597     if (!cb)
   1598         return LayoutRect();
   1599 
   1600     // Now calculate startPos and endPos for painting selection.
   1601     // We include a selection while endPos > 0
   1602     int startPos, endPos;
   1603     if (selectionState() == SelectionInside) {
   1604         // We are fully selected.
   1605         startPos = 0;
   1606         endPos = textLength();
   1607     } else {
   1608         selectionStartEnd(startPos, endPos);
   1609         if (selectionState() == SelectionStart)
   1610             endPos = textLength();
   1611         else if (selectionState() == SelectionEnd)
   1612             startPos = 0;
   1613     }
   1614 
   1615     if (startPos == endPos)
   1616         return IntRect();
   1617 
   1618     LayoutRect rect;
   1619     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
   1620         rect.unite(box->localSelectionRect(startPos, endPos));
   1621         rect.unite(ellipsisRectForBox(box, startPos, endPos));
   1622     }
   1623 
   1624     mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, 0);
   1625     return rect;
   1626 }
   1627 
   1628 int RenderText::caretMinOffset() const
   1629 {
   1630     InlineTextBox* box = firstTextBox();
   1631     if (!box)
   1632         return 0;
   1633     int minOffset = box->start();
   1634     for (box = box->nextTextBox(); box; box = box->nextTextBox())
   1635         minOffset = std::min<int>(minOffset, box->start());
   1636     return minOffset;
   1637 }
   1638 
   1639 int RenderText::caretMaxOffset() const
   1640 {
   1641     InlineTextBox* box = lastTextBox();
   1642     if (!lastTextBox())
   1643         return textLength();
   1644 
   1645     int maxOffset = box->start() + box->len();
   1646     for (box = box->prevTextBox(); box; box = box->prevTextBox())
   1647         maxOffset = std::max<int>(maxOffset, box->start() + box->len());
   1648     return maxOffset;
   1649 }
   1650 
   1651 unsigned RenderText::renderedTextLength() const
   1652 {
   1653     int l = 0;
   1654     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
   1655         l += box->len();
   1656     return l;
   1657 }
   1658 
   1659 int RenderText::previousOffset(int current) const
   1660 {
   1661     if (isAllASCII() || m_text.is8Bit())
   1662         return current - 1;
   1663 
   1664     StringImpl* textImpl = m_text.impl();
   1665     TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
   1666     if (!iterator)
   1667         return current - 1;
   1668 
   1669     long result = iterator->preceding(current);
   1670     if (result == TextBreakDone)
   1671         result = current - 1;
   1672 
   1673 
   1674     return result;
   1675 }
   1676 
   1677 #if OS(POSIX)
   1678 
   1679 #define HANGUL_CHOSEONG_START (0x1100)
   1680 #define HANGUL_CHOSEONG_END (0x115F)
   1681 #define HANGUL_JUNGSEONG_START (0x1160)
   1682 #define HANGUL_JUNGSEONG_END (0x11A2)
   1683 #define HANGUL_JONGSEONG_START (0x11A8)
   1684 #define HANGUL_JONGSEONG_END (0x11F9)
   1685 #define HANGUL_SYLLABLE_START (0xAC00)
   1686 #define HANGUL_SYLLABLE_END (0xD7AF)
   1687 #define HANGUL_JONGSEONG_COUNT (28)
   1688 
   1689 enum HangulState {
   1690     HangulStateL,
   1691     HangulStateV,
   1692     HangulStateT,
   1693     HangulStateLV,
   1694     HangulStateLVT,
   1695     HangulStateBreak
   1696 };
   1697 
   1698 inline bool isHangulLVT(UChar32 character)
   1699 {
   1700     return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
   1701 }
   1702 
   1703 inline bool isMark(UChar32 c)
   1704 {
   1705     int8_t charType = u_charType(c);
   1706     return charType == U_NON_SPACING_MARK || charType == U_ENCLOSING_MARK || charType == U_COMBINING_SPACING_MARK;
   1707 }
   1708 
   1709 inline bool isRegionalIndicator(UChar32 c)
   1710 {
   1711     // National flag emoji each consists of a pair of regional indicator symbols.
   1712     return 0x1F1E6 <= c && c <= 0x1F1FF;
   1713 }
   1714 
   1715 #endif
   1716 
   1717 int RenderText::previousOffsetForBackwardDeletion(int current) const
   1718 {
   1719 #if OS(POSIX)
   1720     ASSERT(m_text);
   1721     StringImpl& text = *m_text.impl();
   1722     UChar32 character;
   1723     bool sawRegionalIndicator = false;
   1724     while (current > 0) {
   1725         if (U16_IS_TRAIL(text[--current]))
   1726             --current;
   1727         if (current < 0)
   1728             break;
   1729 
   1730         UChar32 character = text.characterStartingAt(current);
   1731 
   1732         if (sawRegionalIndicator) {
   1733             // We don't check if the pair of regional indicator symbols before current position can actually be combined
   1734             // into a flag, and just delete it. This may not agree with how the pair is rendered in edge cases,
   1735             // but is good enough in practice.
   1736             if (isRegionalIndicator(character))
   1737                 break;
   1738             // Don't delete a preceding character that isn't a regional indicator symbol.
   1739             U16_FWD_1_UNSAFE(text, current);
   1740         }
   1741 
   1742         // We don't combine characters in Armenian ... Limbu range for backward deletion.
   1743         if ((character >= 0x0530) && (character < 0x1950))
   1744             break;
   1745 
   1746         if (isRegionalIndicator(character)) {
   1747             sawRegionalIndicator = true;
   1748             continue;
   1749         }
   1750 
   1751         if (!isMark(character) && (character != 0xFF9E) && (character != 0xFF9F))
   1752             break;
   1753     }
   1754 
   1755     if (current <= 0)
   1756         return current;
   1757 
   1758     // Hangul
   1759     character = text.characterStartingAt(current);
   1760     if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) {
   1761         HangulState state;
   1762 
   1763         if (character < HANGUL_JUNGSEONG_START)
   1764             state = HangulStateL;
   1765         else if (character < HANGUL_JONGSEONG_START)
   1766             state = HangulStateV;
   1767         else if (character < HANGUL_SYLLABLE_START)
   1768             state = HangulStateT;
   1769         else
   1770             state = isHangulLVT(character) ? HangulStateLVT : HangulStateLV;
   1771 
   1772         while (current > 0 && ((character = text.characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) {
   1773             switch (state) {
   1774             case HangulStateV:
   1775                 if (character <= HANGUL_CHOSEONG_END)
   1776                     state = HangulStateL;
   1777                 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END) && !isHangulLVT(character))
   1778                     state = HangulStateLV;
   1779                 else if (character > HANGUL_JUNGSEONG_END)
   1780                     state = HangulStateBreak;
   1781                 break;
   1782             case HangulStateT:
   1783                 if ((character >= HANGUL_JUNGSEONG_START) && (character <= HANGUL_JUNGSEONG_END))
   1784                     state = HangulStateV;
   1785                 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))
   1786                     state = (isHangulLVT(character) ? HangulStateLVT : HangulStateLV);
   1787                 else if (character < HANGUL_JUNGSEONG_START)
   1788                     state = HangulStateBreak;
   1789                 break;
   1790             default:
   1791                 state = (character < HANGUL_JUNGSEONG_START) ? HangulStateL : HangulStateBreak;
   1792                 break;
   1793             }
   1794             if (state == HangulStateBreak)
   1795                 break;
   1796 
   1797             --current;
   1798         }
   1799     }
   1800 
   1801     return current;
   1802 #else
   1803     // Platforms other than Unix-like delete by one code point.
   1804     if (U16_IS_TRAIL(m_text[--current]))
   1805         --current;
   1806     if (current < 0)
   1807         current = 0;
   1808     return current;
   1809 #endif
   1810 }
   1811 
   1812 int RenderText::nextOffset(int current) const
   1813 {
   1814     if (isAllASCII() || m_text.is8Bit())
   1815         return current + 1;
   1816 
   1817     StringImpl* textImpl = m_text.impl();
   1818     TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
   1819     if (!iterator)
   1820         return current + 1;
   1821 
   1822     long result = iterator->following(current);
   1823     if (result == TextBreakDone)
   1824         result = current + 1;
   1825 
   1826     return result;
   1827 }
   1828 
   1829 bool RenderText::computeCanUseSimpleFontCodePath() const
   1830 {
   1831     if (isAllASCII() || m_text.is8Bit())
   1832         return true;
   1833     return Character::characterRangeCodePath(characters16(), length()) == SimplePath;
   1834 }
   1835 
   1836 #if ENABLE(ASSERT)
   1837 
   1838 void RenderText::checkConsistency() const
   1839 {
   1840 #ifdef CHECK_CONSISTENCY
   1841     const InlineTextBox* prev = 0;
   1842     for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) {
   1843         ASSERT(child->renderer() == this);
   1844         ASSERT(child->prevTextBox() == prev);
   1845         prev = child;
   1846     }
   1847     ASSERT(prev == m_lastTextBox);
   1848 #endif
   1849 }
   1850 
   1851 #endif
   1852 
   1853 void RenderText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset)
   1854 {
   1855     if (!gSecureTextTimers)
   1856         gSecureTextTimers = new SecureTextTimerMap;
   1857 
   1858     SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this);
   1859     if (!secureTextTimer) {
   1860         secureTextTimer = new SecureTextTimer(this);
   1861         gSecureTextTimers->add(this, secureTextTimer);
   1862     }
   1863     secureTextTimer->restartWithNewText(lastTypedCharacterOffset);
   1864 }
   1865 
   1866 PassRefPtr<AbstractInlineTextBox> RenderText::firstAbstractInlineTextBox()
   1867 {
   1868     return AbstractInlineTextBox::getOrCreate(this, m_firstTextBox);
   1869 }
   1870 
   1871 } // namespace blink
   1872