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)
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.
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.
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.
26 #include "RenderText.h"
28 #include "AXObjectCache.h"
29 #include "EllipsisBox.h"
30 #include "FloatQuad.h"
31 #include "FontTranscoder.h"
32 #include "FrameView.h"
33 #include "Hyphenation.h"
34 #include "InlineTextBox.h"
36 #include "RenderArena.h"
37 #include "RenderBlock.h"
38 #include "RenderCombineText.h"
39 #include "RenderLayer.h"
40 #include "RenderView.h"
43 #include "TextBreakIterator.h"
44 #include "TextResourceDecoder.h"
45 #include "VisiblePosition.h"
46 #include "break_lines.h"
47 #include <wtf/text/StringBuffer.h>
48 #include <wtf/unicode/CharacterNames.h>
52 using namespace Unicode;
56 struct SameSizeAsRenderText : public RenderObject {
57 uint32_t bitfields : 16;
63 COMPILE_ASSERT(sizeof(RenderText) == sizeof(SameSizeAsRenderText), RenderText_should_stay_small);
65 class SecureTextTimer;
66 typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap;
67 static SecureTextTimerMap* gSecureTextTimers = 0;
69 class SecureTextTimer : public TimerBase {
71 SecureTextTimer(RenderText* renderText)
72 : m_renderText(renderText)
73 , m_lastTypedCharacterOffset(-1)
77 void restartWithNewText(unsigned lastTypedCharacterOffset)
79 m_lastTypedCharacterOffset = lastTypedCharacterOffset;
80 if (Settings* settings = m_renderText->document()->settings())
81 startOneShot(settings->passwordEchoDurationInSeconds());
83 void invalidate() { m_lastTypedCharacterOffset = -1; }
84 unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; }
89 ASSERT(gSecureTextTimers->contains(m_renderText));
90 m_renderText->setText(m_renderText->text(), true /* forcing setting text as it may be masked later */);
93 RenderText* m_renderText;
94 int m_lastTypedCharacterOffset;
97 static void makeCapitalized(String* string, UChar previous)
102 unsigned length = string->length();
103 const StringImpl& stringImpl = *string->impl();
105 if (length >= numeric_limits<unsigned>::max())
108 StringBuffer<UChar> stringWithPrevious(length + 1);
109 stringWithPrevious[0] = previous == noBreakSpace ? ' ' : previous;
110 for (unsigned i = 1; i < length + 1; i++) {
111 // Replace   with a real space since ICU no longer treats   as a word separator.
112 if (stringImpl[i - 1] == noBreakSpace)
113 stringWithPrevious[i] = ' ';
115 stringWithPrevious[i] = stringImpl[i - 1];
118 TextBreakIterator* boundary = wordBreakIterator(stringWithPrevious.characters(), length + 1);
122 StringBuilder result;
123 result.reserveCapacity(length);
126 int32_t startOfWord = textBreakFirst(boundary);
127 for (endOfWord = textBreakNext(boundary); endOfWord != TextBreakDone; startOfWord = endOfWord, endOfWord = textBreakNext(boundary)) {
128 if (startOfWord) // Ignore first char of previous string
129 result.append(stringImpl[startOfWord - 1] == noBreakSpace ? noBreakSpace : toTitleCase(stringWithPrevious[startOfWord]));
130 for (int i = startOfWord + 1; i < endOfWord; i++)
131 result.append(stringImpl[i - 1]);
134 *string = result.toString();
137 RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
138 : RenderObject(!node || node->isDocumentNode() ? 0 : node)
140 , m_linesDirty(false)
141 , m_containsReversedText(false)
142 , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
143 , m_needsTranscoding(false)
153 // FIXME: Some clients of RenderText (and subclasses) pass Document as node to create anonymous renderer.
154 // They should be switched to passing null and using setDocumentForAnonymous.
155 if (node && node->isDocumentNode())
156 setDocumentForAnonymous(toDocument(node));
158 m_isAllASCII = m_text.containsOnlyASCII();
159 m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
162 view()->frameView()->incrementVisuallyNonEmptyCharacterCount(m_text.length());
167 RenderText::~RenderText()
169 ASSERT(!m_firstTextBox);
170 ASSERT(!m_lastTextBox);
175 const char* RenderText::renderName() const
180 bool RenderText::isTextFragment() const
185 bool RenderText::isWordBreak() const
190 void RenderText::updateNeedsTranscoding()
192 const TextEncoding* encoding = document()->decoder() ? &document()->decoder()->encoding() : 0;
193 m_needsTranscoding = fontTranscoder().needsTranscoding(style()->font().fontDescription(), encoding);
196 void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
198 // There is no need to ever schedule repaints from a style change of a text run, since
199 // we already did this for the parent of the text run.
200 // We do have to schedule layouts, though, since a style change can force us to
202 if (diff == StyleDifferenceLayout) {
203 setNeedsLayoutAndPrefWidthsRecalc();
204 m_knownToHaveNoOverflowAndNoFallbackFonts = false;
207 RenderStyle* newStyle = style();
208 bool needsResetText = false;
210 updateNeedsTranscoding();
211 needsResetText = m_needsTranscoding;
212 } else if (oldStyle->font().needsTranscoding() != newStyle->font().needsTranscoding() || (newStyle->font().needsTranscoding() && oldStyle->font().firstFamily() != newStyle->font().firstFamily())) {
213 updateNeedsTranscoding();
214 needsResetText = true;
217 ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
218 ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
219 if (needsResetText || oldTransform != newStyle->textTransform() || oldSecurity != newStyle->textSecurity())
223 void RenderText::removeAndDestroyTextBoxes()
225 if (!documentBeingDestroyed()) {
226 if (firstTextBox()) {
228 RootInlineBox* next = firstTextBox()->root()->nextRootBox();
232 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
235 parent()->dirtyLinesFromChangedChild(this);
240 void RenderText::willBeDestroyed()
242 if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->take(this) : 0)
243 delete secureTextTimer;
245 removeAndDestroyTextBoxes();
246 RenderObject::willBeDestroyed();
249 void RenderText::extractTextBox(InlineTextBox* box)
253 m_lastTextBox = box->prevTextBox();
254 if (box == m_firstTextBox)
256 if (box->prevTextBox())
257 box->prevTextBox()->setNextTextBox(0);
258 box->setPreviousTextBox(0);
259 for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox())
260 curr->setExtracted();
265 void RenderText::attachTextBox(InlineTextBox* box)
270 m_lastTextBox->setNextTextBox(box);
271 box->setPreviousTextBox(m_lastTextBox);
273 m_firstTextBox = box;
274 InlineTextBox* last = box;
275 for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {
276 curr->setExtracted(false);
279 m_lastTextBox = last;
284 void RenderText::removeTextBox(InlineTextBox* box)
288 if (box == m_firstTextBox)
289 m_firstTextBox = box->nextTextBox();
290 if (box == m_lastTextBox)
291 m_lastTextBox = box->prevTextBox();
292 if (box->nextTextBox())
293 box->nextTextBox()->setPreviousTextBox(box->prevTextBox());
294 if (box->prevTextBox())
295 box->prevTextBox()->setNextTextBox(box->nextTextBox());
300 void RenderText::deleteTextBoxes()
302 if (firstTextBox()) {
303 RenderArena* arena = renderArena();
305 for (InlineTextBox* curr = firstTextBox(); curr; curr = next) {
306 next = curr->nextTextBox();
307 curr->destroy(arena);
309 m_firstTextBox = m_lastTextBox = 0;
313 PassRefPtr<StringImpl> RenderText::originalText() const
316 return (e && e->isTextNode()) ? toText(e)->dataImpl() : 0;
319 void RenderText::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
321 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
322 rects.append(enclosingIntRect(FloatRect(accumulatedOffset + box->topLeft(), box->size())));
325 static FloatRect localQuadForTextBox(InlineTextBox* box, unsigned start, unsigned end, bool useSelectionHeight)
327 unsigned realEnd = min(box->end() + 1, end);
328 LayoutRect r = box->localSelectionRect(start, realEnd);
330 if (!useSelectionHeight) {
331 // Change the height and y position (or width and x for vertical text)
332 // because selectionRect uses selection-specific values.
333 if (box->isHorizontal()) {
334 r.setHeight(box->logicalHeight());
337 r.setWidth(box->logicalWidth());
346 void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
348 // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
349 // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
350 // function to take ints causes various internal mismatches. But selectionRect takes ints, and
351 // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
352 // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
353 ASSERT(end == UINT_MAX || end <= INT_MAX);
354 ASSERT(start <= INT_MAX);
355 start = min(start, static_cast<unsigned>(INT_MAX));
356 end = min(end, static_cast<unsigned>(INT_MAX));
358 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
359 // Note: box->end() returns the index of the last character, not the index past it
360 if (start <= box->start() && box->end() < end) {
361 FloatRect r = box->calculateBoundaries();
362 if (useSelectionHeight) {
363 LayoutRect selectionRect = box->localSelectionRect(start, end);
364 if (box->isHorizontal()) {
365 r.setHeight(selectionRect.height());
366 r.setY(selectionRect.y());
368 r.setWidth(selectionRect.width());
369 r.setX(selectionRect.x());
372 rects.append(localToAbsoluteQuad(r, 0, wasFixed).enclosingBoundingBox());
374 // FIXME: This code is wrong. It's converting local to absolute twice. http://webkit.org/b/65722
375 FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
377 rects.append(localToAbsoluteQuad(rect, 0, wasFixed).enclosingBoundingBox());
382 static IntRect ellipsisRectForBox(InlineTextBox* box, unsigned startPos, unsigned endPos)
387 unsigned short truncation = box->truncation();
388 if (truncation == cNoTruncation)
392 if (EllipsisBox* ellipsis = box->root()->ellipsisBox()) {
393 int ellipsisStartPosition = max<int>(startPos - box->start(), 0);
394 int ellipsisEndPosition = min<int>(endPos - box->start(), box->len());
396 // The ellipsis should be considered to be selected if the end of
397 // the selection is past the beginning of the truncation and the
398 // beginning of the selection is before or at the beginning of the truncation.
399 if (ellipsisEndPosition >= truncation && ellipsisStartPosition <= truncation)
400 return ellipsis->selectionRect();
406 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed, ClippingOption option) const
408 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
409 FloatRect boundaries = box->calculateBoundaries();
411 // Shorten the width of this text box if it ends in an ellipsis.
412 // FIXME: ellipsisRectForBox should switch to return FloatRect soon with the subpixellayout branch.
413 IntRect ellipsisRect = (option == ClipToEllipsis) ? ellipsisRectForBox(box, 0, textLength()) : IntRect();
414 if (!ellipsisRect.isEmpty()) {
415 if (style()->isHorizontalWritingMode())
416 boundaries.setWidth(ellipsisRect.maxX() - boundaries.x());
418 boundaries.setHeight(ellipsisRect.maxY() - boundaries.y());
420 quads.append(localToAbsoluteQuad(boundaries, 0, wasFixed));
424 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
426 absoluteQuads(quads, wasFixed, NoClipping);
429 void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
431 // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
432 // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
433 // function to take ints causes various internal mismatches. But selectionRect takes ints, and
434 // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
435 // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
436 ASSERT(end == UINT_MAX || end <= INT_MAX);
437 ASSERT(start <= INT_MAX);
438 start = min(start, static_cast<unsigned>(INT_MAX));
439 end = min(end, static_cast<unsigned>(INT_MAX));
441 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
442 // Note: box->end() returns the index of the last character, not the index past it
443 if (start <= box->start() && box->end() < end) {
444 FloatRect r = box->calculateBoundaries();
445 if (useSelectionHeight) {
446 LayoutRect selectionRect = box->localSelectionRect(start, end);
447 if (box->isHorizontal()) {
448 r.setHeight(selectionRect.height());
449 r.setY(selectionRect.y());
451 r.setWidth(selectionRect.width());
452 r.setX(selectionRect.x());
455 quads.append(localToAbsoluteQuad(r, 0, wasFixed));
457 FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
459 quads.append(localToAbsoluteQuad(rect, 0, wasFixed));
464 InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const
466 // The text runs point to parts of the RenderText's m_text
467 // (they don't include '\n')
468 // Find the text run that includes the character at offset
469 // and return pos, which is the position of the char in the run.
474 InlineTextBox* s = m_firstTextBox;
476 while (offset > off && s->nextTextBox()) {
477 s = s->nextTextBox();
478 off = s->start() + s->len();
480 // we are now in the correct text run
481 pos = (offset > off ? s->len() : s->len() - (off - offset) );
485 enum ShouldAffinityBeDownstream { AlwaysDownstream, AlwaysUpstream, UpstreamIfPositionIsNotAtStart };
487 static bool lineDirectionPointFitsInBox(int pointLineDirection, InlineTextBox* box, ShouldAffinityBeDownstream& shouldAffinityBeDownstream)
489 shouldAffinityBeDownstream = AlwaysDownstream;
491 // the x coordinate is equal to the left edge of this box
492 // the affinity must be downstream so the position doesn't jump back to the previous line
493 // except when box is the first box in the line
494 if (pointLineDirection <= box->logicalLeft()) {
495 shouldAffinityBeDownstream = !box->prevLeafChild() ? UpstreamIfPositionIsNotAtStart : AlwaysDownstream;
499 // and the x coordinate is to the left of the right edge of this box
500 // check to see if position goes in this box
501 if (pointLineDirection < box->logicalRight()) {
502 shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
506 // box is first on line
507 // and the x coordinate is to the left of the first text box left edge
508 if (!box->prevLeafChildIgnoringLineBreak() && pointLineDirection < box->logicalLeft())
511 if (!box->nextLeafChildIgnoringLineBreak()) {
512 // box is last on line
513 // and the x coordinate is to the right of the last text box right edge
514 // generate VisiblePosition, use UPSTREAM affinity if possible
515 shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
522 static VisiblePosition createVisiblePositionForBox(const InlineBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
524 EAffinity affinity = VP_DEFAULT_AFFINITY;
525 switch (shouldAffinityBeDownstream) {
526 case AlwaysDownstream:
527 affinity = DOWNSTREAM;
530 affinity = VP_UPSTREAM_IF_POSSIBLE;
532 case UpstreamIfPositionIsNotAtStart:
533 affinity = offset > box->caretMinOffset() ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM;
536 return box->renderer()->createVisiblePosition(offset, affinity);
539 static VisiblePosition createVisiblePositionAfterAdjustingOffsetForBiDi(const InlineTextBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
542 ASSERT(box->renderer());
545 if (offset && static_cast<unsigned>(offset) < box->len())
546 return createVisiblePositionForBox(box, box->start() + offset, shouldAffinityBeDownstream);
548 bool positionIsAtStartOfBox = !offset;
549 if (positionIsAtStartOfBox == box->isLeftToRightDirection()) {
550 // offset is on the left edge
552 const InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak();
553 if ((prevBox && prevBox->bidiLevel() == box->bidiLevel())
554 || box->renderer()->containingBlock()->style()->direction() == box->direction()) // FIXME: left on 12CBA
555 return createVisiblePositionForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
557 if (prevBox && prevBox->bidiLevel() > box->bidiLevel()) {
558 // e.g. left of B in aDC12BAb
559 const InlineBox* leftmostBox;
561 leftmostBox = prevBox;
562 prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
563 } while (prevBox && prevBox->bidiLevel() > box->bidiLevel());
564 return createVisiblePositionForBox(leftmostBox, leftmostBox->caretRightmostOffset(), shouldAffinityBeDownstream);
567 if (!prevBox || prevBox->bidiLevel() < box->bidiLevel()) {
568 // e.g. left of D in aDC12BAb
569 const InlineBox* rightmostBox;
570 const InlineBox* nextBox = box;
572 rightmostBox = nextBox;
573 nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
574 } while (nextBox && nextBox->bidiLevel() >= box->bidiLevel());
575 return createVisiblePositionForBox(rightmostBox,
576 box->isLeftToRightDirection() ? rightmostBox->caretMaxOffset() : rightmostBox->caretMinOffset(), shouldAffinityBeDownstream);
579 return createVisiblePositionForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
582 const InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak();
583 if ((nextBox && nextBox->bidiLevel() == box->bidiLevel())
584 || box->renderer()->containingBlock()->style()->direction() == box->direction())
585 return createVisiblePositionForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
587 // offset is on the right edge
588 if (nextBox && nextBox->bidiLevel() > box->bidiLevel()) {
589 // e.g. right of C in aDC12BAb
590 const InlineBox* rightmostBox;
592 rightmostBox = nextBox;
593 nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
594 } while (nextBox && nextBox->bidiLevel() > box->bidiLevel());
595 return createVisiblePositionForBox(rightmostBox, rightmostBox->caretLeftmostOffset(), shouldAffinityBeDownstream);
598 if (!nextBox || nextBox->bidiLevel() < box->bidiLevel()) {
599 // e.g. right of A in aDC12BAb
600 const InlineBox* leftmostBox;
601 const InlineBox* prevBox = box;
603 leftmostBox = prevBox;
604 prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
605 } while (prevBox && prevBox->bidiLevel() >= box->bidiLevel());
606 return createVisiblePositionForBox(leftmostBox,
607 box->isLeftToRightDirection() ? leftmostBox->caretMinOffset() : leftmostBox->caretMaxOffset(), shouldAffinityBeDownstream);
610 return createVisiblePositionForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
613 VisiblePosition RenderText::positionForPoint(const LayoutPoint& point)
615 if (!firstTextBox() || textLength() == 0)
616 return createVisiblePosition(0, DOWNSTREAM);
618 LayoutUnit pointLineDirection = firstTextBox()->isHorizontal() ? point.x() : point.y();
619 LayoutUnit pointBlockDirection = firstTextBox()->isHorizontal() ? point.y() : point.x();
620 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
622 InlineTextBox* lastBox = 0;
623 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
624 if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild() && !box->nextLeafChild()->isLineBreak())
625 box = box->nextTextBox();
627 RootInlineBox* rootBox = box->root();
628 LayoutUnit top = min(rootBox->selectionTop(), rootBox->lineTop());
629 if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirection == top)) {
630 LayoutUnit bottom = rootBox->selectionBottom();
631 if (rootBox->nextRootBox())
632 bottom = min(bottom, rootBox->nextRootBox()->lineTop());
634 if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockDirection == bottom)) {
635 ShouldAffinityBeDownstream shouldAffinityBeDownstream;
636 if (lineDirectionPointFitsInBox(pointLineDirection, box, shouldAffinityBeDownstream))
637 return createVisiblePositionAfterAdjustingOffsetForBiDi(box, box->offsetForPosition(pointLineDirection), shouldAffinityBeDownstream);
644 ShouldAffinityBeDownstream shouldAffinityBeDownstream;
645 lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityBeDownstream);
646 return createVisiblePositionAfterAdjustingOffsetForBiDi(lastBox, lastBox->offsetForPosition(pointLineDirection) + lastBox->start(), shouldAffinityBeDownstream);
648 return createVisiblePosition(0, DOWNSTREAM);
651 LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
656 ASSERT(inlineBox->isInlineTextBox());
657 if (!inlineBox->isInlineTextBox())
660 InlineTextBox* box = toInlineTextBox(inlineBox);
662 int height = box->root()->selectionHeight();
663 int top = box->root()->selectionTop();
665 // Go ahead and round left to snap it to the nearest pixel.
666 float left = box->positionForOffset(caretOffset);
668 // Distribute the caret's width to either side of the offset.
669 int caretWidthLeftOfOffset = caretWidth / 2;
670 left -= caretWidthLeftOfOffset;
671 int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset;
675 float rootLeft = box->root()->logicalLeft();
676 float rootRight = box->root()->logicalRight();
678 // FIXME: should we use the width of the root inline box or the
679 // width of the containing block for this?
680 if (extraWidthToEndOfLine)
681 *extraWidthToEndOfLine = (box->root()->logicalWidth() + rootLeft) - (left + 1);
683 RenderBlock* cb = containingBlock();
684 RenderStyle* cbStyle = cb->style();
688 leftEdge = min<float>(0, rootLeft);
689 rightEdge = max<float>(cb->logicalWidth(), rootRight);
691 bool rightAligned = false;
692 switch (cbStyle->textAlign()) {
704 rightAligned = !cbStyle->isLeftToRightDirection();
707 rightAligned = cbStyle->isLeftToRightDirection();
712 left = max(left, leftEdge);
713 left = min(left, rootRight - caretWidth);
715 left = min(left, rightEdge - caretWidthRightOfOffset);
716 left = max(left, rootLeft);
719 return style()->isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth);
722 ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
724 if (style()->hasTextCombine() && isCombineText()) {
725 const RenderCombineText* combineText = toRenderCombineText(this);
726 if (combineText->isCombined())
727 return combineText->combinedTextWidth(f);
730 if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
731 float monospaceCharacterWidth = f.spaceWidth();
735 StringImpl& text = *m_text.impl();
736 for (int i = start; i < start + len; i++) {
739 if (c == ' ' || c == '\n') {
740 w += monospaceCharacterWidth;
742 } else if (c == '\t') {
743 if (style()->collapseWhiteSpace()) {
744 w += monospaceCharacterWidth;
747 w += f.tabWidth(style()->tabSize(), xPos + w);
753 w += monospaceCharacterWidth;
756 if (isSpace && i > start)
757 w += f.wordSpacing();
762 TextRun run = RenderBlock::constructTextRun(const_cast<RenderText*>(this), f, this, start, len, style());
763 run.setCharactersLength(textLength() - start);
764 ASSERT(run.charactersLength() >= run.length());
766 run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
767 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
769 return f.width(run, fallbackFonts, glyphOverflow);
772 void RenderText::trimmedPrefWidths(float leadWidth,
773 float& beginMinW, bool& beginWS,
774 float& endMinW, bool& endWS,
775 bool& hasBreakableChar, bool& hasBreak,
776 float& beginMaxW, float& endMaxW,
777 float& minW, float& maxW, bool& stripFrontSpaces)
779 bool collapseWhiteSpace = style()->collapseWhiteSpace();
780 if (!collapseWhiteSpace)
781 stripFrontSpaces = false;
783 if (m_hasTab || preferredLogicalWidthsDirty())
784 computePreferredLogicalWidths(leadWidth);
786 beginWS = !stripFrontSpaces && m_hasBeginWS;
789 int len = textLength();
791 if (!len || (stripFrontSpaces && text()->containsOnlyWhitespace())) {
805 beginMinW = m_beginMinWidth;
806 endMinW = m_endMinWidth;
808 hasBreakableChar = m_hasBreakableChar;
809 hasBreak = m_hasBreak;
812 StringImpl& text = *m_text.impl();
813 if (text[0] == ' ' || (text[0] == '\n' && !style()->preserveNewline()) || text[0] == '\t') {
814 const Font& font = style()->font(); // FIXME: This ignores first-line.
815 if (stripFrontSpaces) {
816 const UChar space = ' ';
817 float spaceWidth = font.width(RenderBlock::constructTextRun(this, font, &space, 1, style()));
820 maxW += font.wordSpacing();
823 stripFrontSpaces = collapseWhiteSpace && m_hasEndWS;
825 if (!style()->autoWrap() || minW > maxW)
828 // Compute our max widths by scanning the string for newlines.
830 const Font& f = style()->font(); // FIXME: This ignores first-line.
831 bool firstLine = true;
834 for (int i = 0; i < len; i++) {
836 while (i + linelen < len && text[i + linelen] != '\n')
840 endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW, 0, 0);
847 } else if (firstLine) {
854 // A <pre> run that ends with a newline, as in, e.g.,
855 // <pre>Some text\n\n<span>More text</pre>
861 static inline bool isSpaceAccordingToStyle(UChar c, RenderStyle* style)
863 return c == ' ' || (c == noBreakSpace && style->nbspMode() == SPACE);
866 float RenderText::minLogicalWidth() const
868 if (preferredLogicalWidthsDirty())
869 const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
874 float RenderText::maxLogicalWidth() const
876 if (preferredLogicalWidthsDirty())
877 const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
882 void RenderText::computePreferredLogicalWidths(float leadWidth)
884 HashSet<const SimpleFontData*> fallbackFonts;
885 GlyphOverflow glyphOverflow;
886 computePreferredLogicalWidths(leadWidth, fallbackFonts, glyphOverflow);
887 if (fallbackFonts.isEmpty() && !glyphOverflow.left && !glyphOverflow.right && !glyphOverflow.top && !glyphOverflow.bottom)
888 m_knownToHaveNoOverflowAndNoFallbackFonts = true;
891 static inline float hyphenWidth(RenderText* renderer, const Font& font)
893 RenderStyle* style = renderer->style();
894 return font.width(RenderBlock::constructTextRun(renderer, font, style->hyphenString().string(), style));
897 static float maxWordFragmentWidth(RenderText* renderer, RenderStyle* style, const Font& font, const UChar* word, int wordLength, int minimumPrefixLength, int minimumSuffixLength, int& suffixStart, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
900 if (wordLength <= minimumSuffixLength)
903 Vector<int, 8> hyphenLocations;
904 int hyphenLocation = wordLength - minimumSuffixLength;
905 while ((hyphenLocation = lastHyphenLocation(word, wordLength, hyphenLocation, style->locale())) >= minimumPrefixLength)
906 hyphenLocations.append(hyphenLocation);
908 if (hyphenLocations.isEmpty())
911 hyphenLocations.reverse();
913 float minimumFragmentWidthToConsider = font.pixelSize() * 5 / 4 + hyphenWidth(renderer, font);
914 float maxFragmentWidth = 0;
915 for (size_t k = 0; k < hyphenLocations.size(); ++k) {
916 int fragmentLength = hyphenLocations[k] - suffixStart;
917 StringBuilder fragmentWithHyphen;
918 fragmentWithHyphen.append(word + suffixStart, fragmentLength);
919 fragmentWithHyphen.append(style->hyphenString());
921 TextRun run = RenderBlock::constructTextRun(renderer, font, fragmentWithHyphen.characters(), fragmentWithHyphen.length(), style);
922 run.setCharactersLength(fragmentWithHyphen.length());
923 run.setCharacterScanForCodePath(!renderer->canUseSimpleFontCodePath());
924 float fragmentWidth = font.width(run, &fallbackFonts, &glyphOverflow);
926 // Narrow prefixes are ignored. See tryHyphenating in RenderBlockLineLayout.cpp.
927 if (fragmentWidth <= minimumFragmentWidthToConsider)
930 suffixStart += fragmentLength;
931 maxFragmentWidth = max(maxFragmentWidth, fragmentWidth);
934 return maxFragmentWidth;
937 void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
939 ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts);
949 float currMinWidth = 0;
950 float currMaxWidth = 0;
951 m_hasBreakableChar = false;
954 m_hasBeginWS = false;
957 RenderStyle* styleToUse = style();
958 const Font& f = styleToUse->font(); // FIXME: This ignores first-line.
959 float wordSpacing = styleToUse->wordSpacing();
960 int len = textLength();
961 LazyLineBreakIterator breakIterator(m_text, styleToUse->locale());
962 bool needsWordSpacing = false;
963 bool ignoringSpaces = false;
964 bool isSpace = false;
965 bool firstWord = true;
966 bool firstLine = true;
967 int nextBreakable = -1;
968 int lastWordBoundary = 0;
970 // Non-zero only when kerning is enabled, in which case we measure words with their trailing
971 // space, then subtract its width.
972 float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(RenderBlock::constructTextRun(this, f, &space, 1, styleToUse), &fallbackFonts) + wordSpacing : 0;
974 // If automatic hyphenation is allowed, we keep track of the width of the widest word (or word
975 // fragment) encountered so far, and only try hyphenating words that are wider.
976 float maxWordWidth = numeric_limits<float>::max();
977 int minimumPrefixLength = 0;
978 int minimumSuffixLength = 0;
979 if (styleToUse->hyphens() == HyphensAuto && canHyphenate(styleToUse->locale())) {
982 // Map 'hyphenate-limit-{before,after}: auto;' to 2.
983 minimumPrefixLength = styleToUse->hyphenationLimitBefore();
984 if (minimumPrefixLength < 0)
985 minimumPrefixLength = 2;
987 minimumSuffixLength = styleToUse->hyphenationLimitAfter();
988 if (minimumSuffixLength < 0)
989 minimumSuffixLength = 2;
992 int firstGlyphLeftOverflow = -1;
994 bool breakNBSP = styleToUse->autoWrap() && styleToUse->nbspMode() == SPACE;
995 bool breakAll = (styleToUse->wordBreak() == BreakAllWordBreak || styleToUse->wordBreak() == BreakWordBreak) && styleToUse->autoWrap();
997 for (int i = 0; i < len; i++) {
998 UChar c = characterAt(i);
1000 bool previousCharacterIsSpace = isSpace;
1002 bool isNewline = false;
1004 if (styleToUse->preserveNewline()) {
1010 } else if (c == '\t') {
1011 if (!styleToUse->collapseWhiteSpace()) {
1019 if ((isSpace || isNewline) && !i)
1020 m_hasBeginWS = true;
1021 if ((isSpace || isNewline) && i == len - 1)
1024 if (!ignoringSpaces && styleToUse->collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
1025 ignoringSpaces = true;
1027 if (ignoringSpaces && !isSpace)
1028 ignoringSpaces = false;
1030 // Ignore spaces and soft hyphens
1031 if (ignoringSpaces) {
1032 ASSERT(lastWordBoundary == i);
1035 } else if (c == softHyphen && styleToUse->hyphens() != HyphensNone) {
1036 currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
1037 if (firstGlyphLeftOverflow < 0)
1038 firstGlyphLeftOverflow = glyphOverflow.left;
1039 lastWordBoundary = i + 1;
1043 bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable, breakNBSP);
1044 bool betweenWords = true;
1046 while (c != '\n' && !isSpaceAccordingToStyle(c, styleToUse) && c != '\t' && (c != softHyphen || styleToUse->hyphens() == HyphensNone)) {
1051 if (isBreakable(breakIterator, j, nextBreakable, breakNBSP) && characterAt(j - 1) != softHyphen)
1054 betweenWords = false;
1059 int wordLen = j - i;
1061 bool isSpace = (j < len) && isSpaceAccordingToStyle(c, styleToUse);
1063 if (wordTrailingSpaceWidth && isSpace)
1064 w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth;
1066 w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
1067 if (c == softHyphen && styleToUse->hyphens() != HyphensNone)
1068 currMinWidth += hyphenWidth(this, f);
1071 if (w > maxWordWidth) {
1073 float maxFragmentWidth = maxWordFragmentWidth(this, styleToUse, f, characters() + i, wordLen, minimumPrefixLength, minimumSuffixLength, suffixStart, fallbackFonts, glyphOverflow);
1077 if (wordTrailingSpaceWidth && isSpace)
1078 suffixWidth = widthFromCache(f, i + suffixStart, wordLen - suffixStart + 1, leadWidth + currMaxWidth, 0, 0) - wordTrailingSpaceWidth;
1080 suffixWidth = widthFromCache(f, i + suffixStart, wordLen - suffixStart, leadWidth + currMaxWidth, 0, 0);
1082 maxFragmentWidth = max(maxFragmentWidth, suffixWidth);
1084 currMinWidth += maxFragmentWidth - w;
1085 maxWordWidth = max(maxWordWidth, maxFragmentWidth);
1090 if (firstGlyphLeftOverflow < 0)
1091 firstGlyphLeftOverflow = glyphOverflow.left;
1094 if (lastWordBoundary == i)
1097 currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
1098 lastWordBoundary = j;
1101 bool isCollapsibleWhiteSpace = (j < len) && styleToUse->isCollapsibleWhiteSpace(c);
1102 if (j < len && styleToUse->autoWrap())
1103 m_hasBreakableChar = true;
1105 // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
1106 // last word in the run.
1107 if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
1108 currMaxWidth += wordSpacing;
1112 // If the first character in the run is breakable, then we consider ourselves to have a beginning
1113 // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
1114 // being appended to a previous text run when considering the total minimum width of the containing block.
1116 m_hasBreakableChar = true;
1117 m_beginMinWidth = hasBreak ? 0 : currMinWidth;
1119 m_endMinWidth = currMinWidth;
1121 if (currMinWidth > m_minWidth)
1122 m_minWidth = currMinWidth;
1127 // Nowrap can never be broken, so don't bother setting the
1128 // breakable character boolean. Pre can only be broken if we encounter a newline.
1129 if (style()->autoWrap() || isNewline)
1130 m_hasBreakableChar = true;
1132 if (currMinWidth > m_minWidth)
1133 m_minWidth = currMinWidth;
1136 if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
1140 if (!styleToUse->autoWrap())
1141 m_beginMinWidth = currMaxWidth;
1144 if (currMaxWidth > m_maxWidth)
1145 m_maxWidth = currMaxWidth;
1148 TextRun run = RenderBlock::constructTextRun(this, f, this, i, 1, styleToUse);
1149 run.setCharactersLength(len - i);
1150 ASSERT(run.charactersLength() >= run.length());
1151 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
1152 run.setXPos(leadWidth + currMaxWidth);
1154 currMaxWidth += f.width(run, &fallbackFonts);
1155 glyphOverflow.right = 0;
1156 needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
1158 ASSERT(lastWordBoundary == i);
1163 if (firstGlyphLeftOverflow > 0)
1164 glyphOverflow.left = firstGlyphLeftOverflow;
1166 if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord))
1167 currMaxWidth += wordSpacing;
1169 m_minWidth = max(currMinWidth, m_minWidth);
1170 m_maxWidth = max(currMaxWidth, m_maxWidth);
1172 if (!styleToUse->autoWrap())
1173 m_minWidth = m_maxWidth;
1175 if (styleToUse->whiteSpace() == PRE) {
1177 m_beginMinWidth = m_maxWidth;
1178 m_endMinWidth = currMaxWidth;
1181 setPreferredLogicalWidthsDirty(false);
1184 bool RenderText::isAllCollapsibleWhitespace() const
1186 unsigned length = textLength();
1188 for (unsigned i = 0; i < length; ++i) {
1189 if (!style()->isCollapsibleWhiteSpace(characters8()[i]))
1194 for (unsigned i = 0; i < length; ++i) {
1195 if (!style()->isCollapsibleWhiteSpace(characters16()[i]))
1201 bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
1204 StringImpl& text = *m_text.impl();
1206 for (currPos = from;
1207 currPos < from + len && (text[currPos] == '\n' || text[currPos] == ' ' || text[currPos] == '\t');
1209 return currPos >= (from + len);
1212 FloatPoint RenderText::firstRunOrigin() const
1214 return IntPoint(firstRunX(), firstRunY());
1217 float RenderText::firstRunX() const
1219 return m_firstTextBox ? m_firstTextBox->x() : 0;
1222 float RenderText::firstRunY() const
1224 return m_firstTextBox ? m_firstTextBox->y() : 0;
1227 void RenderText::setSelectionState(SelectionState state)
1229 RenderObject::setSelectionState(state);
1231 if (canUpdateSelectionOnRootLineBoxes()) {
1232 if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) {
1233 int startPos, endPos;
1234 selectionStartEnd(startPos, endPos);
1235 if (selectionState() == SelectionStart) {
1236 endPos = textLength();
1238 // to handle selection from end of text to end of line
1239 if (startPos && startPos == endPos)
1240 startPos = endPos - 1;
1241 } else if (selectionState() == SelectionEnd)
1244 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1245 if (box->isSelected(startPos, endPos)) {
1246 RootInlineBox* root = box->root();
1248 root->setHasSelectedChildren(true);
1252 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1253 RootInlineBox* root = box->root();
1255 root->setHasSelectedChildren(state == SelectionInside);
1260 // The containing block can be null in case of an orphaned tree.
1261 RenderBlock* containingBlock = this->containingBlock();
1262 if (containingBlock && !containingBlock->isRenderView())
1263 containingBlock->setSelectionState(state);
1266 void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force)
1268 if (!force && equal(m_text.impl(), text.get()))
1271 unsigned oldLen = textLength();
1272 unsigned newLen = text->length();
1273 int delta = newLen - oldLen;
1274 unsigned end = len ? offset + len - 1 : offset;
1276 RootInlineBox* firstRootBox = 0;
1277 RootInlineBox* lastRootBox = 0;
1279 bool dirtiedLines = false;
1281 // Dirty all text boxes that include characters in between offset and offset+len.
1282 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1283 // FIXME: This shouldn't rely on the end of a dirty line box. See https://bugs.webkit.org/show_bug.cgi?id=97264
1284 // Text run is entirely before the affected range.
1285 if (curr->end() < offset)
1288 // Text run is entirely after the affected range.
1289 if (curr->start() > end) {
1290 curr->offsetRun(delta);
1291 RootInlineBox* root = curr->root();
1292 if (!firstRootBox) {
1293 firstRootBox = root;
1294 if (!dirtiedLines) {
1295 // The affected area was in between two runs. Go ahead and mark the root box of
1296 // the run after the affected area as dirty.
1297 firstRootBox->markDirty();
1298 dirtiedLines = true;
1302 } else if (curr->end() >= offset && curr->end() <= end) {
1303 // Text run overlaps with the left end of the affected range.
1304 curr->dirtyLineBoxes();
1305 dirtiedLines = true;
1306 } else if (curr->start() <= offset && curr->end() >= end) {
1307 // Text run subsumes the affected range.
1308 curr->dirtyLineBoxes();
1309 dirtiedLines = true;
1310 } else if (curr->start() <= end && curr->end() >= end) {
1311 // Text run overlaps with right end of the affected range.
1312 curr->dirtyLineBoxes();
1313 dirtiedLines = true;
1317 // Now we have to walk all of the clean lines and adjust their cached line break information
1318 // to reflect our updated offsets.
1320 lastRootBox = lastRootBox->nextRootBox();
1322 RootInlineBox* prev = firstRootBox->prevRootBox();
1324 firstRootBox = prev;
1325 } else if (lastTextBox()) {
1326 ASSERT(!lastRootBox);
1327 firstRootBox = lastTextBox()->root();
1328 firstRootBox->markDirty();
1329 dirtiedLines = true;
1331 for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
1332 if (curr->lineBreakObj() == this && curr->lineBreakPos() > end)
1333 curr->setLineBreakPos(curr->lineBreakPos() + delta);
1336 // If the text node is empty, dirty the line where new text will be inserted.
1337 if (!firstTextBox() && parent()) {
1338 parent()->dirtyLinesFromChangedChild(this);
1339 dirtiedLines = true;
1342 m_linesDirty = dirtiedLines;
1343 setText(text, force || dirtiedLines);
1346 void RenderText::transformText()
1348 if (RefPtr<StringImpl> textToTransform = originalText())
1349 setText(textToTransform.release(), true);
1352 static inline bool isInlineFlowOrEmptyText(const RenderObject* o)
1354 if (o->isRenderInline())
1358 StringImpl* text = toRenderText(o)->text();
1361 return !text->length();
1364 UChar RenderText::previousCharacter() const
1366 // find previous text renderer if one exists
1367 const RenderObject* previousText = this;
1368 while ((previousText = previousText->previousInPreOrder()))
1369 if (!isInlineFlowOrEmptyText(previousText))
1372 if (previousText && previousText->isText())
1373 if (StringImpl* previousString = toRenderText(previousText)->text())
1374 prev = (*previousString)[previousString->length() - 1];
1378 void applyTextTransform(const RenderStyle* style, String& text, UChar previousCharacter)
1383 switch (style->textTransform()) {
1387 makeCapitalized(&text, previousCharacter);
1398 void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
1402 if (m_needsTranscoding) {
1403 const TextEncoding* encoding = document()->decoder() ? &document()->decoder()->encoding() : 0;
1404 fontTranscoder().convert(m_text, style()->font().fontDescription(), encoding);
1409 applyTextTransform(style(), m_text, previousCharacter());
1411 // We use the same characters here as for list markers.
1412 // See the listMarkerText function in RenderListMarker.cpp.
1413 switch (style()->textSecurity()) {
1417 secureText(whiteBullet);
1423 secureText(blackSquare);
1428 ASSERT(!isBR() || (textLength() == 1 && m_text[0] == '\n'));
1430 m_isAllASCII = m_text.containsOnlyASCII();
1431 m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
1434 void RenderText::secureText(UChar mask)
1436 if (!m_text.length())
1439 int lastTypedCharacterOffsetToReveal = -1;
1440 String revealedText;
1441 SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->get(this) : 0;
1442 if (secureTextTimer && secureTextTimer->isActive()) {
1443 lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOffset();
1444 if (lastTypedCharacterOffsetToReveal >= 0)
1445 revealedText.append(m_text[lastTypedCharacterOffsetToReveal]);
1449 if (lastTypedCharacterOffsetToReveal >= 0) {
1450 m_text.replace(lastTypedCharacterOffsetToReveal, 1, revealedText);
1451 // m_text may be updated later before timer fires. We invalidate the lastTypedCharacterOffset to avoid inconsistency.
1452 secureTextTimer->invalidate();
1456 void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
1460 if (!force && equal(m_text.impl(), text.get()))
1463 setTextInternal(text);
1464 setNeedsLayoutAndPrefWidthsRecalc();
1465 m_knownToHaveNoOverflowAndNoFallbackFonts = false;
1467 if (AXObjectCache* cache = document()->existingAXObjectCache())
1468 cache->textChanged(this);
1471 String RenderText::textWithoutTranscoding() const
1473 // If m_text isn't transcoded or is secure, we can just return the modified text.
1474 if (!m_needsTranscoding || style()->textSecurity() != TSNONE)
1477 // Otherwise, we should use original text. If text-transform is
1478 // specified, we should transform the text on the fly.
1479 String text = originalText();
1480 applyTextTransform(style(), text, previousCharacter());
1484 void RenderText::dirtyLineBoxes(bool fullLayout)
1488 else if (!m_linesDirty) {
1489 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1490 box->dirtyLineBoxes();
1492 m_linesDirty = false;
1495 InlineTextBox* RenderText::createTextBox()
1497 return new (renderArena()) InlineTextBox(this);
1500 InlineTextBox* RenderText::createInlineTextBox()
1502 InlineTextBox* textBox = createTextBox();
1503 if (!m_firstTextBox)
1504 m_firstTextBox = m_lastTextBox = textBox;
1506 m_lastTextBox->setNextTextBox(textBox);
1507 textBox->setPreviousTextBox(m_lastTextBox);
1508 m_lastTextBox = textBox;
1510 textBox->setIsText(true);
1514 void RenderText::positionLineBox(InlineBox* box)
1516 InlineTextBox* s = toInlineTextBox(box);
1518 // FIXME: should not be needed!!!
1520 // We want the box to be destroyed.
1522 if (m_firstTextBox == s)
1523 m_firstTextBox = s->nextTextBox();
1525 s->prevTextBox()->setNextTextBox(s->nextTextBox());
1526 if (m_lastTextBox == s)
1527 m_lastTextBox = s->prevTextBox();
1529 s->nextTextBox()->setPreviousTextBox(s->prevTextBox());
1530 s->destroy(renderArena());
1534 m_containsReversedText |= !s->isLeftToRightDirection();
1537 float RenderText::width(unsigned from, unsigned len, float xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1539 if (from >= textLength())
1542 if (from + len > textLength())
1543 len = textLength() - from;
1545 return width(from, len, style(firstLine)->font(), xPos, fallbackFonts, glyphOverflow);
1548 float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1550 ASSERT(from + len <= textLength());
1555 if (&f == &style()->font()) {
1556 if (!style()->preserveNewline() && !from && len == textLength() && (!glyphOverflow || !glyphOverflow->computeBounds)) {
1557 if (fallbackFonts) {
1558 ASSERT(glyphOverflow);
1559 if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
1560 const_cast<RenderText*>(this)->computePreferredLogicalWidths(0, *fallbackFonts, *glyphOverflow);
1561 if (fallbackFonts->isEmpty() && !glyphOverflow->left && !glyphOverflow->right && !glyphOverflow->top && !glyphOverflow->bottom)
1562 m_knownToHaveNoOverflowAndNoFallbackFonts = true;
1566 w = maxLogicalWidth();
1568 w = widthFromCache(f, from, len, xPos, fallbackFonts, glyphOverflow);
1570 TextRun run = RenderBlock::constructTextRun(const_cast<RenderText*>(this), f, this, from, len, style());
1571 run.setCharactersLength(textLength() - from);
1572 ASSERT(run.charactersLength() >= run.length());
1574 run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
1575 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
1577 w = f.width(run, fallbackFonts, glyphOverflow);
1583 IntRect RenderText::linesBoundingBox() const
1587 ASSERT(!firstTextBox() == !lastTextBox()); // Either both are null or both exist.
1588 if (firstTextBox() && lastTextBox()) {
1589 // Return the width of the minimal left side and the maximal right side.
1590 float logicalLeftSide = 0;
1591 float logicalRightSide = 0;
1592 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1593 if (curr == firstTextBox() || curr->logicalLeft() < logicalLeftSide)
1594 logicalLeftSide = curr->logicalLeft();
1595 if (curr == firstTextBox() || curr->logicalRight() > logicalRightSide)
1596 logicalRightSide = curr->logicalRight();
1599 bool isHorizontal = style()->isHorizontalWritingMode();
1601 float x = isHorizontal ? logicalLeftSide : firstTextBox()->x();
1602 float y = isHorizontal ? firstTextBox()->y() : logicalLeftSide;
1603 float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTextBox()->logicalBottom() - x;
1604 float height = isHorizontal ? lastTextBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
1605 result = enclosingIntRect(FloatRect(x, y, width, height));
1611 LayoutRect RenderText::linesVisualOverflowBoundingBox() const
1613 if (!firstTextBox())
1614 return LayoutRect();
1616 // Return the width of the minimal left side and the maximal right side.
1617 LayoutUnit logicalLeftSide = LayoutUnit::max();
1618 LayoutUnit logicalRightSide = LayoutUnit::min();
1619 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1620 logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
1621 logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
1624 LayoutUnit logicalTop = firstTextBox()->logicalTopVisualOverflow();
1625 LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
1626 LayoutUnit logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - logicalTop;
1628 LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
1629 if (!style()->isHorizontalWritingMode())
1630 rect = rect.transposedRect();
1634 LayoutRect RenderText::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
1636 RenderObject* rendererToRepaint = containingBlock();
1638 // Do not cross self-painting layer boundaries.
1639 RenderObject* enclosingLayerRenderer = enclosingLayer()->renderer();
1640 if (enclosingLayerRenderer != rendererToRepaint && !rendererToRepaint->isDescendantOf(enclosingLayerRenderer))
1641 rendererToRepaint = enclosingLayerRenderer;
1643 // The renderer we chose to repaint may be an ancestor of repaintContainer, but we need to do a repaintContainer-relative repaint.
1644 if (repaintContainer && repaintContainer != rendererToRepaint && !rendererToRepaint->isDescendantOf(repaintContainer))
1645 return repaintContainer->clippedOverflowRectForRepaint(repaintContainer);
1647 return rendererToRepaint->clippedOverflowRectForRepaint(repaintContainer);
1650 LayoutRect RenderText::selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent)
1652 ASSERT(!needsLayout());
1654 if (selectionState() == SelectionNone)
1655 return LayoutRect();
1656 RenderBlock* cb = containingBlock();
1658 return LayoutRect();
1660 // Now calculate startPos and endPos for painting selection.
1661 // We include a selection while endPos > 0
1662 int startPos, endPos;
1663 if (selectionState() == SelectionInside) {
1664 // We are fully selected.
1666 endPos = textLength();
1668 selectionStartEnd(startPos, endPos);
1669 if (selectionState() == SelectionStart)
1670 endPos = textLength();
1671 else if (selectionState() == SelectionEnd)
1675 if (startPos == endPos)
1679 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1680 rect.unite(box->localSelectionRect(startPos, endPos));
1681 rect.unite(ellipsisRectForBox(box, startPos, endPos));
1684 if (clipToVisibleContent)
1685 computeRectForRepaint(repaintContainer, rect);
1687 if (cb->hasColumns())
1688 cb->adjustRectForColumns(rect);
1690 rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox();
1696 int RenderText::caretMinOffset() const
1698 InlineTextBox* box = firstTextBox();
1701 int minOffset = box->start();
1702 for (box = box->nextTextBox(); box; box = box->nextTextBox())
1703 minOffset = min<int>(minOffset, box->start());
1707 int RenderText::caretMaxOffset() const
1709 InlineTextBox* box = lastTextBox();
1711 return textLength();
1713 int maxOffset = box->start() + box->len();
1714 for (box = box->prevTextBox(); box; box = box->prevTextBox())
1715 maxOffset = max<int>(maxOffset, box->start() + box->len());
1719 unsigned RenderText::renderedTextLength() const
1722 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1727 int RenderText::previousOffset(int current) const
1729 if (isAllASCII() || m_text.is8Bit())
1732 StringImpl* textImpl = m_text.impl();
1733 TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
1737 long result = textBreakPreceding(iterator, current);
1738 if (result == TextBreakDone)
1739 result = current - 1;
1747 #define HANGUL_CHOSEONG_START (0x1100)
1748 #define HANGUL_CHOSEONG_END (0x115F)
1749 #define HANGUL_JUNGSEONG_START (0x1160)
1750 #define HANGUL_JUNGSEONG_END (0x11A2)
1751 #define HANGUL_JONGSEONG_START (0x11A8)
1752 #define HANGUL_JONGSEONG_END (0x11F9)
1753 #define HANGUL_SYLLABLE_START (0xAC00)
1754 #define HANGUL_SYLLABLE_END (0xD7AF)
1755 #define HANGUL_JONGSEONG_COUNT (28)
1766 inline bool isHangulLVT(UChar32 character)
1768 return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
1771 inline bool isMark(UChar32 c)
1773 int8_t charType = u_charType(c);
1774 return charType == U_NON_SPACING_MARK || charType == U_ENCLOSING_MARK || charType == U_COMBINING_SPACING_MARK;
1777 inline bool isRegionalIndicator(UChar32 c)
1779 // National flag emoji each consists of a pair of regional indicator symbols.
1780 return 0x1F1E6 <= c && c <= 0x1F1FF;
1785 int RenderText::previousOffsetForBackwardDeletion(int current) const
1789 StringImpl& text = *m_text.impl();
1791 bool sawRegionalIndicator = false;
1792 while (current > 0) {
1793 if (U16_IS_TRAIL(text[--current]))
1798 UChar32 character = text.characterStartingAt(current);
1800 if (sawRegionalIndicator) {
1801 // We don't check if the pair of regional indicator symbols before current position can actually be combined
1802 // into a flag, and just delete it. This may not agree with how the pair is rendered in edge cases,
1803 // but is good enough in practice.
1804 if (isRegionalIndicator(character))
1806 // Don't delete a preceding character that isn't a regional indicator symbol.
1807 U16_FWD_1_UNSAFE(text, current);
1810 // We don't combine characters in Armenian ... Limbu range for backward deletion.
1811 if ((character >= 0x0530) && (character < 0x1950))
1814 if (isRegionalIndicator(character)) {
1815 sawRegionalIndicator = true;
1819 if (!isMark(character) && (character != 0xFF9E) && (character != 0xFF9F))
1827 character = text.characterStartingAt(current);
1828 if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) {
1830 HangulState initialState;
1832 if (character < HANGUL_JUNGSEONG_START)
1833 state = HangulStateL;
1834 else if (character < HANGUL_JONGSEONG_START)
1835 state = HangulStateV;
1836 else if (character < HANGUL_SYLLABLE_START)
1837 state = HangulStateT;
1839 state = isHangulLVT(character) ? HangulStateLVT : HangulStateLV;
1841 initialState = state;
1843 while (current > 0 && ((character = text.characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) {
1846 if (character <= HANGUL_CHOSEONG_END)
1847 state = HangulStateL;
1848 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END) && !isHangulLVT(character))
1849 state = HangulStateLV;
1850 else if (character > HANGUL_JUNGSEONG_END)
1851 state = HangulStateBreak;
1854 if ((character >= HANGUL_JUNGSEONG_START) && (character <= HANGUL_JUNGSEONG_END))
1855 state = HangulStateV;
1856 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))
1857 state = (isHangulLVT(character) ? HangulStateLVT : HangulStateLV);
1858 else if (character < HANGUL_JUNGSEONG_START)
1859 state = HangulStateBreak;
1862 state = (character < HANGUL_JUNGSEONG_START) ? HangulStateL : HangulStateBreak;
1865 if (state == HangulStateBreak)
1874 // Platforms other than Mac delete by one code point.
1875 if (U16_IS_TRAIL(m_text[--current]))
1883 int RenderText::nextOffset(int current) const
1885 if (isAllASCII() || m_text.is8Bit())
1888 StringImpl* textImpl = m_text.impl();
1889 TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
1893 long result = textBreakFollowing(iterator, current);
1894 if (result == TextBreakDone)
1895 result = current + 1;
1900 bool RenderText::computeCanUseSimpleFontCodePath() const
1902 if (isAllASCII() || m_text.is8Bit())
1904 return Font::characterRangeCodePath(characters(), length()) == Font::Simple;
1909 void RenderText::checkConsistency() const
1911 #ifdef CHECK_CONSISTENCY
1912 const InlineTextBox* prev = 0;
1913 for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) {
1914 ASSERT(child->renderer() == this);
1915 ASSERT(child->prevTextBox() == prev);
1918 ASSERT(prev == m_lastTextBox);
1924 void RenderText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset)
1926 if (!gSecureTextTimers)
1927 gSecureTextTimers = new SecureTextTimerMap;
1929 SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this);
1930 if (!secureTextTimer) {
1931 secureTextTimer = new SecureTextTimer(this);
1932 gSecureTextTimers->add(this, secureTextTimer);
1934 secureTextTimer->restartWithNewText(lastTypedCharacterOffset);
1937 } // namespace WebCore