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