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 "core/rendering/RenderText.h"
28 #include "core/accessibility/AXObjectCache.h"
29 #include "core/dom/Text.h"
30 #include "core/editing/TextIterator.h"
31 #include "core/frame/FrameView.h"
32 #include "core/frame/Settings.h"
33 #include "core/html/parser/TextResourceDecoder.h"
34 #include "core/rendering/AbstractInlineTextBox.h"
35 #include "core/rendering/EllipsisBox.h"
36 #include "core/rendering/InlineTextBox.h"
37 #include "core/rendering/RenderBlock.h"
38 #include "core/rendering/RenderCombineText.h"
39 #include "core/rendering/RenderLayer.h"
40 #include "core/rendering/RenderView.h"
41 #include "core/rendering/break_lines.h"
42 #include "platform/fonts/Character.h"
43 #include "platform/geometry/FloatQuad.h"
44 #include "platform/text/BidiResolver.h"
45 #include "platform/text/TextBreakIterator.h"
46 #include "platform/text/TextRunIterator.h"
47 #include "wtf/text/StringBuffer.h"
48 #include "wtf/text/StringBuilder.h"
49 #include "wtf/unicode/CharacterNames.h"
53 using namespace Unicode;
57 struct SameSizeAsRenderText : public RenderObject {
58 uint32_t bitfields : 16;
64 COMPILE_ASSERT(sizeof(RenderText) == sizeof(SameSizeAsRenderText), RenderText_should_stay_small);
66 class SecureTextTimer;
67 typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap;
68 static SecureTextTimerMap* gSecureTextTimers = 0;
70 class SecureTextTimer FINAL : public TimerBase {
72 SecureTextTimer(RenderText* renderText)
73 : m_renderText(renderText)
74 , m_lastTypedCharacterOffset(-1)
78 void restartWithNewText(unsigned lastTypedCharacterOffset)
80 m_lastTypedCharacterOffset = lastTypedCharacterOffset;
81 if (Settings* settings = m_renderText->document().settings())
82 startOneShot(settings->passwordEchoDurationInSeconds());
84 void invalidate() { m_lastTypedCharacterOffset = -1; }
85 unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; }
88 virtual void fired() OVERRIDE
90 ASSERT(gSecureTextTimers->contains(m_renderText));
91 m_renderText->setText(m_renderText->text().impl(), true /* forcing setting text as it may be masked later */);
94 RenderText* m_renderText;
95 int m_lastTypedCharacterOffset;
98 static void makeCapitalized(String* string, UChar previous)
100 if (string->isNull())
103 unsigned length = string->length();
104 const StringImpl& input = *string->impl();
106 if (length >= numeric_limits<unsigned>::max())
109 StringBuffer<UChar> stringWithPrevious(length + 1);
110 stringWithPrevious[0] = previous == noBreakSpace ? ' ' : previous;
111 for (unsigned i = 1; i < length + 1; i++) {
112 // Replace   with a real space since ICU no longer treats   as a word separator.
113 if (input[i - 1] == noBreakSpace)
114 stringWithPrevious[i] = ' ';
116 stringWithPrevious[i] = input[i - 1];
119 TextBreakIterator* boundary = wordBreakIterator(stringWithPrevious.characters(), length + 1);
123 StringBuilder result;
124 result.reserveCapacity(length);
127 int32_t startOfWord = boundary->first();
128 for (endOfWord = boundary->next(); endOfWord != TextBreakDone; startOfWord = endOfWord, endOfWord = boundary->next()) {
129 if (startOfWord) // Ignore first char of previous string
130 result.append(input[startOfWord - 1] == noBreakSpace ? noBreakSpace : toTitleCase(stringWithPrevious[startOfWord]));
131 for (int i = startOfWord + 1; i < endOfWord; i++)
132 result.append(input[i - 1]);
135 *string = result.toString();
138 RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
139 : RenderObject(!node || node->isDocumentNode() ? 0 : node)
141 , m_linesDirty(false)
142 , m_containsReversedText(false)
143 , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
146 , m_firstLineMinWidth(0)
147 , m_lastLineLineMinWidth(0)
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::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
192 // There is no need to ever schedule repaints from a style change of a text run, since
193 // we already did this for the parent of the text run.
194 // We do have to schedule layouts, though, since a style change can force us to
196 if (diff == StyleDifferenceLayout) {
197 setNeedsLayoutAndPrefWidthsRecalc();
198 m_knownToHaveNoOverflowAndNoFallbackFonts = false;
201 RenderStyle* newStyle = style();
202 ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
203 ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
204 if (oldTransform != newStyle->textTransform() || oldSecurity != newStyle->textSecurity())
207 if (!text().containsOnlyWhitespace())
208 newStyle->font().willUseFontData();
211 void RenderText::removeAndDestroyTextBoxes()
213 if (!documentBeingDestroyed()) {
214 if (firstTextBox()) {
216 RootInlineBox* next = firstTextBox()->root()->nextRootBox();
220 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
223 parent()->dirtyLinesFromChangedChild(this);
228 void RenderText::willBeDestroyed()
230 if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->take(this) : 0)
231 delete secureTextTimer;
233 removeAndDestroyTextBoxes();
234 RenderObject::willBeDestroyed();
237 void RenderText::extractTextBox(InlineTextBox* box)
241 m_lastTextBox = box->prevTextBox();
242 if (box == m_firstTextBox)
244 if (box->prevTextBox())
245 box->prevTextBox()->setNextTextBox(0);
246 box->setPreviousTextBox(0);
247 for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox())
248 curr->setExtracted();
253 void RenderText::attachTextBox(InlineTextBox* box)
258 m_lastTextBox->setNextTextBox(box);
259 box->setPreviousTextBox(m_lastTextBox);
261 m_firstTextBox = box;
262 InlineTextBox* last = box;
263 for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {
264 curr->setExtracted(false);
267 m_lastTextBox = last;
272 void RenderText::removeTextBox(InlineTextBox* box)
276 if (box == m_firstTextBox)
277 m_firstTextBox = box->nextTextBox();
278 if (box == m_lastTextBox)
279 m_lastTextBox = box->prevTextBox();
280 if (box->nextTextBox())
281 box->nextTextBox()->setPreviousTextBox(box->prevTextBox());
282 if (box->prevTextBox())
283 box->prevTextBox()->setNextTextBox(box->nextTextBox());
288 void RenderText::deleteTextBoxes()
290 if (firstTextBox()) {
292 for (InlineTextBox* curr = firstTextBox(); curr; curr = next) {
293 next = curr->nextTextBox();
296 m_firstTextBox = m_lastTextBox = 0;
300 PassRefPtr<StringImpl> RenderText::originalText() const
303 return (e && e->isTextNode()) ? toText(e)->dataImpl() : 0;
306 String RenderText::plainText() const
309 return WebCore::plainText(rangeOfContents(node()).get());
311 // FIXME: this is just a stopgap until TextIterator is adapted to support generated text.
312 StringBuilder plainTextBuilder;
313 for (InlineTextBox* textBox = firstTextBox(); textBox; textBox = textBox->nextTextBox()) {
314 String text = m_text.substring(textBox->start(), textBox->len()).simplifyWhiteSpace(WTF::DoNotStripWhiteSpace);
315 plainTextBuilder.append(text);
316 if (textBox->nextTextBox() && textBox->nextTextBox()->start() > textBox->end() && text.length() && !text.right(1).containsOnlyWhitespace())
317 plainTextBuilder.append(" ");
319 return plainTextBuilder.toString();
322 void RenderText::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
324 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
325 rects.append(enclosingIntRect(FloatRect(accumulatedOffset + box->topLeft(), box->size())));
328 static FloatRect localQuadForTextBox(InlineTextBox* box, unsigned start, unsigned end, bool useSelectionHeight)
330 unsigned realEnd = min(box->end() + 1, end);
331 LayoutRect r = box->localSelectionRect(start, realEnd);
333 if (!useSelectionHeight) {
334 // Change the height and y position (or width and x for vertical text)
335 // because selectionRect uses selection-specific values.
336 if (box->isHorizontal()) {
337 r.setHeight(box->height());
340 r.setWidth(box->width());
349 void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
351 // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
352 // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
353 // function to take ints causes various internal mismatches. But selectionRect takes ints, and
354 // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
355 // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
356 ASSERT(end == UINT_MAX || end <= INT_MAX);
357 ASSERT(start <= INT_MAX);
358 start = min(start, static_cast<unsigned>(INT_MAX));
359 end = min(end, static_cast<unsigned>(INT_MAX));
361 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
362 // Note: box->end() returns the index of the last character, not the index past it
363 if (start <= box->start() && box->end() < end) {
364 FloatRect r = box->calculateBoundaries();
365 if (useSelectionHeight) {
366 LayoutRect selectionRect = box->localSelectionRect(start, end);
367 if (box->isHorizontal()) {
368 r.setHeight(selectionRect.height());
369 r.setY(selectionRect.y());
371 r.setWidth(selectionRect.width());
372 r.setX(selectionRect.x());
375 rects.append(localToAbsoluteQuad(r, 0, wasFixed).enclosingBoundingBox());
377 // FIXME: This code is wrong. It's converting local to absolute twice. http://webkit.org/b/65722
378 FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
380 rects.append(localToAbsoluteQuad(rect, 0, wasFixed).enclosingBoundingBox());
385 static IntRect ellipsisRectForBox(InlineTextBox* box, unsigned startPos, unsigned endPos)
390 unsigned short truncation = box->truncation();
391 if (truncation == cNoTruncation)
395 if (EllipsisBox* ellipsis = box->root()->ellipsisBox()) {
396 int ellipsisStartPosition = max<int>(startPos - box->start(), 0);
397 int ellipsisEndPosition = min<int>(endPos - box->start(), box->len());
399 // The ellipsis should be considered to be selected if the end of
400 // the selection is past the beginning of the truncation and the
401 // beginning of the selection is before or at the beginning of the truncation.
402 if (ellipsisEndPosition >= truncation && ellipsisStartPosition <= truncation)
403 return ellipsis->selectionRect();
409 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed, ClippingOption option) const
411 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
412 FloatRect boundaries = box->calculateBoundaries();
414 // Shorten the width of this text box if it ends in an ellipsis.
415 // FIXME: ellipsisRectForBox should switch to return FloatRect soon with the subpixellayout branch.
416 IntRect ellipsisRect = (option == ClipToEllipsis) ? ellipsisRectForBox(box, 0, textLength()) : IntRect();
417 if (!ellipsisRect.isEmpty()) {
418 if (style()->isHorizontalWritingMode())
419 boundaries.setWidth(ellipsisRect.maxX() - boundaries.x());
421 boundaries.setHeight(ellipsisRect.maxY() - boundaries.y());
423 quads.append(localToAbsoluteQuad(boundaries, 0, wasFixed));
427 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
429 absoluteQuads(quads, wasFixed, NoClipping);
432 void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
434 // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
435 // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
436 // function to take ints causes various internal mismatches. But selectionRect takes ints, and
437 // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
438 // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
439 ASSERT(end == UINT_MAX || end <= INT_MAX);
440 ASSERT(start <= INT_MAX);
441 start = min(start, static_cast<unsigned>(INT_MAX));
442 end = min(end, static_cast<unsigned>(INT_MAX));
444 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
445 // Note: box->end() returns the index of the last character, not the index past it
446 if (start <= box->start() && box->end() < end) {
447 FloatRect r = box->calculateBoundaries();
448 if (useSelectionHeight) {
449 LayoutRect selectionRect = box->localSelectionRect(start, end);
450 if (box->isHorizontal()) {
451 r.setHeight(selectionRect.height());
452 r.setY(selectionRect.y());
454 r.setWidth(selectionRect.width());
455 r.setX(selectionRect.x());
458 quads.append(localToAbsoluteQuad(r, 0, wasFixed));
460 FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
462 quads.append(localToAbsoluteQuad(rect, 0, wasFixed));
467 InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const
469 // The text runs point to parts of the RenderText's m_text
470 // (they don't include '\n')
471 // Find the text run that includes the character at offset
472 // and return pos, which is the position of the char in the run.
477 InlineTextBox* s = m_firstTextBox;
479 while (offset > off && s->nextTextBox()) {
480 s = s->nextTextBox();
481 off = s->start() + s->len();
483 // we are now in the correct text run
484 pos = (offset > off ? s->len() : s->len() - (off - offset) );
488 enum ShouldAffinityBeDownstream { AlwaysDownstream, AlwaysUpstream, UpstreamIfPositionIsNotAtStart };
490 static bool lineDirectionPointFitsInBox(int pointLineDirection, InlineTextBox* box, ShouldAffinityBeDownstream& shouldAffinityBeDownstream)
492 shouldAffinityBeDownstream = AlwaysDownstream;
494 // the x coordinate is equal to the left edge of this box
495 // the affinity must be downstream so the position doesn't jump back to the previous line
496 // except when box is the first box in the line
497 if (pointLineDirection <= box->logicalLeft()) {
498 shouldAffinityBeDownstream = !box->prevLeafChild() ? UpstreamIfPositionIsNotAtStart : AlwaysDownstream;
502 // and the x coordinate is to the left of the right edge of this box
503 // check to see if position goes in this box
504 if (pointLineDirection < box->logicalRight()) {
505 shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
509 // box is first on line
510 // and the x coordinate is to the left of the first text box left edge
511 if (!box->prevLeafChildIgnoringLineBreak() && pointLineDirection < box->logicalLeft())
514 if (!box->nextLeafChildIgnoringLineBreak()) {
515 // box is last on line
516 // and the x coordinate is to the right of the last text box right edge
517 // generate VisiblePosition, use UPSTREAM affinity if possible
518 shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
525 static PositionWithAffinity createPositionWithAffinityForBox(const InlineBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
527 EAffinity affinity = VP_DEFAULT_AFFINITY;
528 switch (shouldAffinityBeDownstream) {
529 case AlwaysDownstream:
530 affinity = DOWNSTREAM;
533 affinity = VP_UPSTREAM_IF_POSSIBLE;
535 case UpstreamIfPositionIsNotAtStart:
536 affinity = offset > box->caretMinOffset() ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM;
539 int textStartOffset = box->renderer()->isText() ? toRenderText(box->renderer())->textStartOffset() : 0;
540 return box->renderer()->createPositionWithAffinity(offset + textStartOffset, affinity);
543 static PositionWithAffinity createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(const InlineTextBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
546 ASSERT(box->renderer());
549 if (offset && static_cast<unsigned>(offset) < box->len())
550 return createPositionWithAffinityForBox(box, box->start() + offset, shouldAffinityBeDownstream);
552 bool positionIsAtStartOfBox = !offset;
553 if (positionIsAtStartOfBox == box->isLeftToRightDirection()) {
554 // offset is on the left edge
556 const InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak();
557 if ((prevBox && prevBox->bidiLevel() == box->bidiLevel())
558 || box->renderer()->containingBlock()->style()->direction() == box->direction()) // FIXME: left on 12CBA
559 return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
561 if (prevBox && prevBox->bidiLevel() > box->bidiLevel()) {
562 // e.g. left of B in aDC12BAb
563 const InlineBox* leftmostBox;
565 leftmostBox = prevBox;
566 prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
567 } while (prevBox && prevBox->bidiLevel() > box->bidiLevel());
568 return createPositionWithAffinityForBox(leftmostBox, leftmostBox->caretRightmostOffset(), shouldAffinityBeDownstream);
571 if (!prevBox || prevBox->bidiLevel() < box->bidiLevel()) {
572 // e.g. left of D in aDC12BAb
573 const InlineBox* rightmostBox;
574 const InlineBox* nextBox = box;
576 rightmostBox = nextBox;
577 nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
578 } while (nextBox && nextBox->bidiLevel() >= box->bidiLevel());
579 return createPositionWithAffinityForBox(rightmostBox,
580 box->isLeftToRightDirection() ? rightmostBox->caretMaxOffset() : rightmostBox->caretMinOffset(), shouldAffinityBeDownstream);
583 return createPositionWithAffinityForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
586 const InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak();
587 if ((nextBox && nextBox->bidiLevel() == box->bidiLevel())
588 || box->renderer()->containingBlock()->style()->direction() == box->direction())
589 return createPositionWithAffinityForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
591 // offset is on the right edge
592 if (nextBox && nextBox->bidiLevel() > box->bidiLevel()) {
593 // e.g. right of C in aDC12BAb
594 const InlineBox* rightmostBox;
596 rightmostBox = nextBox;
597 nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
598 } while (nextBox && nextBox->bidiLevel() > box->bidiLevel());
599 return createPositionWithAffinityForBox(rightmostBox, rightmostBox->caretLeftmostOffset(), shouldAffinityBeDownstream);
602 if (!nextBox || nextBox->bidiLevel() < box->bidiLevel()) {
603 // e.g. right of A in aDC12BAb
604 const InlineBox* leftmostBox;
605 const InlineBox* prevBox = box;
607 leftmostBox = prevBox;
608 prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
609 } while (prevBox && prevBox->bidiLevel() >= box->bidiLevel());
610 return createPositionWithAffinityForBox(leftmostBox,
611 box->isLeftToRightDirection() ? leftmostBox->caretMinOffset() : leftmostBox->caretMaxOffset(), shouldAffinityBeDownstream);
614 return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
617 PositionWithAffinity RenderText::positionForPoint(const LayoutPoint& point)
619 if (!firstTextBox() || textLength() == 0)
620 return createPositionWithAffinity(0, DOWNSTREAM);
622 LayoutUnit pointLineDirection = firstTextBox()->isHorizontal() ? point.x() : point.y();
623 LayoutUnit pointBlockDirection = firstTextBox()->isHorizontal() ? point.y() : point.x();
624 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
626 InlineTextBox* lastBox = 0;
627 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
628 if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild() && !box->nextLeafChild()->isLineBreak())
629 box = box->nextTextBox();
631 RootInlineBox* rootBox = box->root();
632 LayoutUnit top = min(rootBox->selectionTop(), rootBox->lineTop());
633 if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirection == top)) {
634 LayoutUnit bottom = rootBox->selectionBottom();
635 if (rootBox->nextRootBox())
636 bottom = min(bottom, rootBox->nextRootBox()->lineTop());
638 if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockDirection == bottom)) {
639 ShouldAffinityBeDownstream shouldAffinityBeDownstream;
640 if (lineDirectionPointFitsInBox(pointLineDirection, box, shouldAffinityBeDownstream))
641 return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(box, box->offsetForPosition(pointLineDirection), shouldAffinityBeDownstream);
648 ShouldAffinityBeDownstream shouldAffinityBeDownstream;
649 lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityBeDownstream);
650 return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastBox, lastBox->offsetForPosition(pointLineDirection) + lastBox->start(), shouldAffinityBeDownstream);
652 return createPositionWithAffinity(0, DOWNSTREAM);
655 LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
660 ASSERT(inlineBox->isInlineTextBox());
661 if (!inlineBox->isInlineTextBox())
664 InlineTextBox* box = toInlineTextBox(inlineBox);
666 int height = box->root()->selectionHeight();
667 int top = box->root()->selectionTop();
669 // Go ahead and round left to snap it to the nearest pixel.
670 float left = box->positionForOffset(caretOffset);
672 // Distribute the caret's width to either side of the offset.
673 int caretWidthLeftOfOffset = caretWidth / 2;
674 left -= caretWidthLeftOfOffset;
675 int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset;
679 float rootLeft = box->root()->logicalLeft();
680 float rootRight = box->root()->logicalRight();
682 // FIXME: should we use the width of the root inline box or the
683 // width of the containing block for this?
684 if (extraWidthToEndOfLine)
685 *extraWidthToEndOfLine = (box->root()->logicalWidth() + rootLeft) - (left + 1);
687 RenderBlock* cb = containingBlock();
688 RenderStyle* cbStyle = cb->style();
692 leftEdge = min<float>(0, rootLeft);
693 rightEdge = max<float>(cb->logicalWidth(), rootRight);
695 bool rightAligned = false;
696 switch (cbStyle->textAlign()) {
708 rightAligned = !cbStyle->isLeftToRightDirection();
711 rightAligned = cbStyle->isLeftToRightDirection();
716 left = max(left, leftEdge);
717 left = min(left, rootRight - caretWidth);
719 left = min(left, rightEdge - caretWidthRightOfOffset);
720 left = max(left, rootLeft);
723 return style()->isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth);
726 ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
728 if (style()->hasTextCombine() && isCombineText()) {
729 const RenderCombineText* combineText = toRenderCombineText(this);
730 if (combineText->isCombined())
731 return combineText->combinedTextWidth(f);
734 if (f.isFixedPitch() && !f.fontDescription().smallCaps() && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
735 float monospaceCharacterWidth = f.spaceWidth();
739 StringImpl& text = *m_text.impl();
740 for (int i = start; i < start + len; i++) {
743 if (c == ' ' || c == '\n') {
744 w += monospaceCharacterWidth;
746 } else if (c == '\t') {
747 if (style()->collapseWhiteSpace()) {
748 w += monospaceCharacterWidth;
751 w += f.tabWidth(style()->tabSize(), xPos + w);
757 w += monospaceCharacterWidth;
760 if (isSpace && i > start)
761 w += f.fontDescription().wordSpacing();
766 TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, start, len, style(), textDirection);
767 run.setCharactersLength(textLength() - start);
768 ASSERT(run.charactersLength() >= run.length());
770 run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
771 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
773 return f.width(run, fallbackFonts, glyphOverflow);
776 void RenderText::trimmedPrefWidths(float leadWidth,
777 float& firstLineMinWidth, bool& hasBreakableStart,
778 float& lastLineMinWidth, bool& hasBreakableEnd,
779 bool& hasBreakableChar, bool& hasBreak,
780 float& firstLineMaxWidth, float& lastLineMaxWidth,
781 float& minWidth, float& maxWidth, bool& stripFrontSpaces,
782 TextDirection direction)
784 bool collapseWhiteSpace = style()->collapseWhiteSpace();
785 if (!collapseWhiteSpace)
786 stripFrontSpaces = false;
788 if (m_hasTab || preferredLogicalWidthsDirty())
789 computePreferredLogicalWidths(leadWidth);
791 hasBreakableStart = !stripFrontSpaces && m_hasBreakableStart;
792 hasBreakableEnd = m_hasBreakableEnd;
794 int len = textLength();
796 if (!len || (stripFrontSpaces && text().impl()->containsOnlyWhitespace())) {
797 firstLineMinWidth = 0;
798 lastLineMinWidth = 0;
799 firstLineMaxWidth = 0;
800 lastLineMaxWidth = 0;
807 minWidth = m_minWidth;
808 maxWidth = m_maxWidth;
810 firstLineMinWidth = m_firstLineMinWidth;
811 lastLineMinWidth = m_lastLineLineMinWidth;
813 hasBreakableChar = m_hasBreakableChar;
814 hasBreak = m_hasBreak;
817 StringImpl& text = *m_text.impl();
818 if (text[0] == ' ' || (text[0] == '\n' && !style()->preserveNewline()) || text[0] == '\t') {
819 const Font& font = style()->font(); // FIXME: This ignores first-line.
820 if (stripFrontSpaces) {
821 const UChar space = ' ';
822 float spaceWidth = font.width(RenderBlockFlow::constructTextRun(this, font, &space, 1, style(), direction));
823 maxWidth -= spaceWidth;
825 maxWidth += font.fontDescription().wordSpacing();
829 stripFrontSpaces = collapseWhiteSpace && m_hasEndWhiteSpace;
831 if (!style()->autoWrap() || minWidth > maxWidth)
834 // Compute our max widths by scanning the string for newlines.
836 const Font& f = style()->font(); // FIXME: This ignores first-line.
837 bool firstLine = true;
838 firstLineMaxWidth = maxWidth;
839 lastLineMaxWidth = maxWidth;
840 for (int i = 0; i < len; i++) {
842 while (i + linelen < len && text[i + linelen] != '\n')
846 lastLineMaxWidth = widthFromCache(f, i, linelen, leadWidth + lastLineMaxWidth, direction, 0, 0);
850 firstLineMaxWidth = lastLineMaxWidth;
853 } else if (firstLine) {
854 firstLineMaxWidth = 0;
860 // A <pre> run that ends with a newline, as in, e.g.,
861 // <pre>Some text\n\n<span>More text</pre>
862 lastLineMaxWidth = 0;
868 float RenderText::minLogicalWidth() const
870 if (preferredLogicalWidthsDirty())
871 const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
876 float RenderText::maxLogicalWidth() const
878 if (preferredLogicalWidthsDirty())
879 const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
884 void RenderText::computePreferredLogicalWidths(float leadWidth)
886 HashSet<const SimpleFontData*> fallbackFonts;
887 GlyphOverflow glyphOverflow;
888 computePreferredLogicalWidths(leadWidth, fallbackFonts, glyphOverflow);
889 if (fallbackFonts.isEmpty() && !glyphOverflow.left && !glyphOverflow.right && !glyphOverflow.top && !glyphOverflow.bottom)
890 m_knownToHaveNoOverflowAndNoFallbackFonts = true;
893 static inline float hyphenWidth(RenderText* renderer, const Font& font, TextDirection direction)
895 RenderStyle* style = renderer->style();
896 return font.width(RenderBlockFlow::constructTextRun(renderer, font, style->hyphenString().string(), style, direction));
899 void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
901 ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts);
905 m_firstLineMinWidth = 0;
906 m_lastLineLineMinWidth = 0;
911 float currMinWidth = 0;
912 float currMaxWidth = 0;
913 m_hasBreakableChar = false;
916 m_hasBreakableStart = false;
917 m_hasBreakableEnd = false;
918 m_hasEndWhiteSpace = false;
920 RenderStyle* styleToUse = style();
921 const Font& f = styleToUse->font(); // FIXME: This ignores first-line.
922 float wordSpacing = styleToUse->wordSpacing();
923 int len = textLength();
924 LazyLineBreakIterator breakIterator(m_text, styleToUse->locale());
925 bool needsWordSpacing = false;
926 bool ignoringSpaces = false;
927 bool isSpace = false;
928 bool firstWord = true;
929 bool firstLine = true;
930 int nextBreakable = -1;
931 int lastWordBoundary = 0;
933 // Non-zero only when kerning is enabled, in which case we measure words with their trailing
934 // space, then subtract its width.
935 float wordTrailingSpaceWidth = f.fontDescription().typesettingFeatures() & Kerning ? f.width(RenderBlockFlow::constructTextRun(this, f, &space, 1, styleToUse, LTR)) + wordSpacing : 0;
937 // If automatic hyphenation is allowed, we keep track of the width of the widest word (or word
938 // fragment) encountered so far, and only try hyphenating words that are wider.
939 float maxWordWidth = numeric_limits<float>::max();
940 int firstGlyphLeftOverflow = -1;
942 bool breakAll = (styleToUse->wordBreak() == BreakAllWordBreak || styleToUse->wordBreak() == BreakWordBreak) && styleToUse->autoWrap();
944 TextRun textRun(text());
945 BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
946 bidiResolver.setStatus(BidiStatus(textRun.direction(), textRun.directionalOverride()));
947 bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&textRun, 0));
948 bool hardLineBreak = false;
949 bool reorderRuns = false;
950 bidiResolver.createBidiRunsForLine(TextRunIterator(&textRun, textRun.length()), NoVisualOverride, hardLineBreak, reorderRuns);
952 BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
953 BidiCharacterRun* run = bidiRuns.firstRun();
954 for (int i = 0; i < len; i++) {
955 UChar c = uncheckedCharacterAt(i);
957 while (i > run->stop())
961 ASSERT(i >= run->start() && i <= run->stop());
962 TextDirection textDirection = run->direction();
964 bool previousCharacterIsSpace = isSpace;
965 bool isNewline = false;
967 if (styleToUse->preserveNewline()) {
973 } else if (c == '\t') {
974 if (!styleToUse->collapseWhiteSpace()) {
982 bool isBreakableLocation = isNewline || (isSpace && styleToUse->autoWrap());
984 m_hasBreakableStart = isBreakableLocation;
986 m_hasBreakableEnd = isBreakableLocation;
987 m_hasEndWhiteSpace = isNewline || isSpace;
990 if (!ignoringSpaces && styleToUse->collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
991 ignoringSpaces = true;
993 if (ignoringSpaces && !isSpace)
994 ignoringSpaces = false;
996 // Ignore spaces and soft hyphens
997 if (ignoringSpaces) {
998 ASSERT(lastWordBoundary == i);
1001 } else if (c == softHyphen) {
1002 currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
1003 if (firstGlyphLeftOverflow < 0)
1004 firstGlyphLeftOverflow = glyphOverflow.left;
1005 lastWordBoundary = i + 1;
1009 bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable);
1010 bool betweenWords = true;
1012 while (c != '\n' && c != ' ' && c != '\t' && (c != softHyphen)) {
1016 c = uncheckedCharacterAt(j);
1017 if (isBreakable(breakIterator, j, nextBreakable) && characterAt(j - 1) != softHyphen)
1020 betweenWords = false;
1025 // Terminate word boundary at bidi run boundary.
1026 j = min(j, run->stop() + 1);
1027 int wordLen = j - i;
1029 bool isSpace = (j < len) && c == ' ';
1031 if (wordTrailingSpaceWidth && isSpace)
1032 w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth;
1034 w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
1035 if (c == softHyphen)
1036 currMinWidth += hyphenWidth(this, f, textDirection);
1039 maxWordWidth = max(maxWordWidth, w);
1041 if (firstGlyphLeftOverflow < 0)
1042 firstGlyphLeftOverflow = glyphOverflow.left;
1045 if (lastWordBoundary == i)
1048 currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
1049 lastWordBoundary = j;
1052 bool isCollapsibleWhiteSpace = (j < len) && styleToUse->isCollapsibleWhiteSpace(c);
1053 if (j < len && styleToUse->autoWrap())
1054 m_hasBreakableChar = true;
1056 // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
1057 // last word in the run.
1058 if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
1059 currMaxWidth += wordSpacing;
1063 // If the first character in the run is breakable, then we consider ourselves to have a beginning
1064 // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
1065 // being appended to a previous text run when considering the total minimum width of the containing block.
1067 m_hasBreakableChar = true;
1068 m_firstLineMinWidth = hasBreak ? 0 : currMinWidth;
1070 m_lastLineLineMinWidth = currMinWidth;
1072 if (currMinWidth > m_minWidth)
1073 m_minWidth = currMinWidth;
1078 // Nowrap can never be broken, so don't bother setting the
1079 // breakable character boolean. Pre can only be broken if we encounter a newline.
1080 if (style()->autoWrap() || isNewline)
1081 m_hasBreakableChar = true;
1083 if (currMinWidth > m_minWidth)
1084 m_minWidth = currMinWidth;
1087 if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
1091 if (!styleToUse->autoWrap())
1092 m_firstLineMinWidth = currMaxWidth;
1095 if (currMaxWidth > m_maxWidth)
1096 m_maxWidth = currMaxWidth;
1099 TextRun run = RenderBlockFlow::constructTextRun(this, f, this, i, 1, styleToUse, textDirection);
1100 run.setCharactersLength(len - i);
1101 ASSERT(run.charactersLength() >= run.length());
1102 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
1103 run.setXPos(leadWidth + currMaxWidth);
1105 currMaxWidth += f.width(run);
1106 glyphOverflow.right = 0;
1107 needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
1109 ASSERT(lastWordBoundary == i);
1113 bidiRuns.deleteRuns();
1115 if (firstGlyphLeftOverflow > 0)
1116 glyphOverflow.left = firstGlyphLeftOverflow;
1118 if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord))
1119 currMaxWidth += wordSpacing;
1121 m_minWidth = max(currMinWidth, m_minWidth);
1122 m_maxWidth = max(currMaxWidth, m_maxWidth);
1124 if (!styleToUse->autoWrap())
1125 m_minWidth = m_maxWidth;
1127 if (styleToUse->whiteSpace() == PRE) {
1129 m_firstLineMinWidth = m_maxWidth;
1130 m_lastLineLineMinWidth = currMaxWidth;
1133 clearPreferredLogicalWidthsDirty();
1136 bool RenderText::isAllCollapsibleWhitespace() const
1138 unsigned length = textLength();
1140 for (unsigned i = 0; i < length; ++i) {
1141 if (!style()->isCollapsibleWhiteSpace(characters8()[i]))
1146 for (unsigned i = 0; i < length; ++i) {
1147 if (!style()->isCollapsibleWhiteSpace(characters16()[i]))
1153 bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
1156 StringImpl& text = *m_text.impl();
1158 for (currPos = from;
1159 currPos < from + len && (text[currPos] == '\n' || text[currPos] == ' ' || text[currPos] == '\t');
1161 return currPos >= (from + len);
1164 FloatPoint RenderText::firstRunOrigin() const
1166 return IntPoint(firstRunX(), firstRunY());
1169 float RenderText::firstRunX() const
1171 return m_firstTextBox ? m_firstTextBox->x() : 0;
1174 float RenderText::firstRunY() const
1176 return m_firstTextBox ? m_firstTextBox->y() : 0;
1179 void RenderText::setSelectionState(SelectionState state)
1181 RenderObject::setSelectionState(state);
1183 if (canUpdateSelectionOnRootLineBoxes()) {
1184 if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) {
1185 int startPos, endPos;
1186 selectionStartEnd(startPos, endPos);
1187 if (selectionState() == SelectionStart) {
1188 endPos = textLength();
1190 // to handle selection from end of text to end of line
1191 if (startPos && startPos == endPos)
1192 startPos = endPos - 1;
1193 } else if (selectionState() == SelectionEnd)
1196 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1197 if (box->isSelected(startPos, endPos)) {
1198 RootInlineBox* root = box->root();
1200 root->setHasSelectedChildren(true);
1204 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1205 RootInlineBox* root = box->root();
1207 root->setHasSelectedChildren(state == SelectionInside);
1212 // The containing block can be null in case of an orphaned tree.
1213 RenderBlock* containingBlock = this->containingBlock();
1214 if (containingBlock && !containingBlock->isRenderView())
1215 containingBlock->setSelectionState(state);
1218 void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force)
1220 if (!force && equal(m_text.impl(), text.get()))
1223 unsigned oldLen = textLength();
1224 unsigned newLen = text->length();
1225 int delta = newLen - oldLen;
1226 unsigned end = len ? offset + len - 1 : offset;
1228 RootInlineBox* firstRootBox = 0;
1229 RootInlineBox* lastRootBox = 0;
1231 bool dirtiedLines = false;
1233 // Dirty all text boxes that include characters in between offset and offset+len.
1234 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1235 // FIXME: This shouldn't rely on the end of a dirty line box. See https://bugs.webkit.org/show_bug.cgi?id=97264
1236 // Text run is entirely before the affected range.
1237 if (curr->end() < offset)
1240 // Text run is entirely after the affected range.
1241 if (curr->start() > end) {
1242 curr->offsetRun(delta);
1243 RootInlineBox* root = curr->root();
1244 if (!firstRootBox) {
1245 firstRootBox = root;
1246 // The affected area was in between two runs. Go ahead and mark the root box of
1247 // the run after the affected area as dirty.
1248 firstRootBox->markDirty();
1249 dirtiedLines = true;
1252 } else if (curr->end() >= offset && curr->end() <= end) {
1253 // Text run overlaps with the left end of the affected range.
1254 curr->dirtyLineBoxes();
1255 dirtiedLines = true;
1256 } else if (curr->start() <= offset && curr->end() >= end) {
1257 // Text run subsumes the affected range.
1258 curr->dirtyLineBoxes();
1259 dirtiedLines = true;
1260 } else if (curr->start() <= end && curr->end() >= end) {
1261 // Text run overlaps with right end of the affected range.
1262 curr->dirtyLineBoxes();
1263 dirtiedLines = true;
1267 // Now we have to walk all of the clean lines and adjust their cached line break information
1268 // to reflect our updated offsets.
1270 lastRootBox = lastRootBox->nextRootBox();
1272 RootInlineBox* prev = firstRootBox->prevRootBox();
1274 firstRootBox = prev;
1275 } else if (lastTextBox()) {
1276 ASSERT(!lastRootBox);
1277 firstRootBox = lastTextBox()->root();
1278 firstRootBox->markDirty();
1279 dirtiedLines = true;
1281 for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
1282 if (curr->lineBreakObj() == this && curr->lineBreakPos() > end)
1283 curr->setLineBreakPos(clampToInteger(curr->lineBreakPos() + delta));
1286 // If the text node is empty, dirty the line where new text will be inserted.
1287 if (!firstTextBox() && parent()) {
1288 parent()->dirtyLinesFromChangedChild(this);
1289 dirtiedLines = true;
1292 m_linesDirty = dirtiedLines;
1293 setText(text, force || dirtiedLines);
1296 void RenderText::transformText()
1298 if (RefPtr<StringImpl> textToTransform = originalText())
1299 setText(textToTransform.release(), true);
1302 static inline bool isInlineFlowOrEmptyText(const RenderObject* o)
1304 if (o->isRenderInline())
1308 return toRenderText(o)->text().isEmpty();
1311 UChar RenderText::previousCharacter() const
1313 // find previous text renderer if one exists
1314 const RenderObject* previousText = this;
1315 while ((previousText = previousText->previousInPreOrder()))
1316 if (!isInlineFlowOrEmptyText(previousText))
1319 if (previousText && previousText->isText())
1320 if (StringImpl* previousString = toRenderText(previousText)->text().impl())
1321 prev = (*previousString)[previousString->length() - 1];
1325 void RenderText::addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
1327 // Text nodes aren't event targets, so don't descend any further.
1330 void applyTextTransform(const RenderStyle* style, String& text, UChar previousCharacter)
1335 switch (style->textTransform()) {
1339 makeCapitalized(&text, previousCharacter);
1342 text = text.upper(style->locale());
1345 text = text.lower(style->locale());
1350 void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
1356 applyTextTransform(style(), m_text, previousCharacter());
1358 // We use the same characters here as for list markers.
1359 // See the listMarkerText function in RenderListMarker.cpp.
1360 switch (style()->textSecurity()) {
1364 secureText(whiteBullet);
1370 secureText(blackSquare);
1375 ASSERT(!isBR() || (textLength() == 1 && m_text[0] == '\n'));
1377 m_isAllASCII = m_text.containsOnlyASCII();
1378 m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
1381 void RenderText::secureText(UChar mask)
1383 if (!m_text.length())
1386 int lastTypedCharacterOffsetToReveal = -1;
1388 SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->get(this) : 0;
1389 if (secureTextTimer && secureTextTimer->isActive()) {
1390 lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOffset();
1391 if (lastTypedCharacterOffsetToReveal >= 0)
1392 revealedText = m_text[lastTypedCharacterOffsetToReveal];
1396 if (lastTypedCharacterOffsetToReveal >= 0) {
1397 m_text.replace(lastTypedCharacterOffsetToReveal, 1, String(&revealedText, 1));
1398 // m_text may be updated later before timer fires. We invalidate the lastTypedCharacterOffset to avoid inconsistency.
1399 secureTextTimer->invalidate();
1403 void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
1407 if (!force && equal(m_text.impl(), text.get()))
1410 setTextInternal(text);
1411 // If preferredLogicalWidthsDirty() of an orphan child is true, RenderObjectChildList::
1412 // insertChildNode() fails to set true to owner. To avoid that, we call
1413 // setNeedsLayoutAndPrefWidthsRecalc() only if this RenderText has parent.
1415 setNeedsLayoutAndPrefWidthsRecalc();
1416 m_knownToHaveNoOverflowAndNoFallbackFonts = false;
1418 if (AXObjectCache* cache = document().existingAXObjectCache())
1419 cache->textChanged(this);
1422 void RenderText::dirtyLineBoxes(bool fullLayout)
1426 else if (!m_linesDirty) {
1427 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1428 box->dirtyLineBoxes();
1430 m_linesDirty = false;
1433 InlineTextBox* RenderText::createTextBox()
1435 return new InlineTextBox(this);
1438 InlineTextBox* RenderText::createInlineTextBox()
1440 InlineTextBox* textBox = createTextBox();
1441 if (!m_firstTextBox)
1442 m_firstTextBox = m_lastTextBox = textBox;
1444 m_lastTextBox->setNextTextBox(textBox);
1445 textBox->setPreviousTextBox(m_lastTextBox);
1446 m_lastTextBox = textBox;
1448 textBox->setIsText(true);
1452 void RenderText::positionLineBox(InlineBox* box)
1454 InlineTextBox* s = toInlineTextBox(box);
1456 // FIXME: should not be needed!!!
1458 // We want the box to be destroyed.
1460 if (m_firstTextBox == s)
1461 m_firstTextBox = s->nextTextBox();
1463 s->prevTextBox()->setNextTextBox(s->nextTextBox());
1464 if (m_lastTextBox == s)
1465 m_lastTextBox = s->prevTextBox();
1467 s->nextTextBox()->setPreviousTextBox(s->prevTextBox());
1472 m_containsReversedText |= !s->isLeftToRightDirection();
1475 float RenderText::width(unsigned from, unsigned len, float xPos, TextDirection textDirection, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1477 if (from >= textLength())
1480 if (from + len > textLength())
1481 len = textLength() - from;
1483 return width(from, len, style(firstLine)->font(), xPos, textDirection, fallbackFonts, glyphOverflow);
1486 float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1488 ASSERT(from + len <= textLength());
1493 if (&f == &style()->font()) {
1494 if (!style()->preserveNewline() && !from && len == textLength() && (!glyphOverflow || !glyphOverflow->computeBounds)) {
1495 if (fallbackFonts) {
1496 ASSERT(glyphOverflow);
1497 if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
1498 const_cast<RenderText*>(this)->computePreferredLogicalWidths(0, *fallbackFonts, *glyphOverflow);
1499 if (fallbackFonts->isEmpty() && !glyphOverflow->left && !glyphOverflow->right && !glyphOverflow->top && !glyphOverflow->bottom)
1500 m_knownToHaveNoOverflowAndNoFallbackFonts = true;
1504 w = maxLogicalWidth();
1506 w = widthFromCache(f, from, len, xPos, textDirection, fallbackFonts, glyphOverflow);
1509 TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, from, len, style(), textDirection);
1510 run.setCharactersLength(textLength() - from);
1511 ASSERT(run.charactersLength() >= run.length());
1513 run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
1514 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
1516 w = f.width(run, fallbackFonts, glyphOverflow);
1522 IntRect RenderText::linesBoundingBox() const
1526 ASSERT(!firstTextBox() == !lastTextBox()); // Either both are null or both exist.
1527 if (firstTextBox() && lastTextBox()) {
1528 // Return the width of the minimal left side and the maximal right side.
1529 float logicalLeftSide = 0;
1530 float logicalRightSide = 0;
1531 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1532 if (curr == firstTextBox() || curr->logicalLeft() < logicalLeftSide)
1533 logicalLeftSide = curr->logicalLeft();
1534 if (curr == firstTextBox() || curr->logicalRight() > logicalRightSide)
1535 logicalRightSide = curr->logicalRight();
1538 bool isHorizontal = style()->isHorizontalWritingMode();
1540 float x = isHorizontal ? logicalLeftSide : firstTextBox()->x();
1541 float y = isHorizontal ? firstTextBox()->y() : logicalLeftSide;
1542 float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTextBox()->logicalBottom() - x;
1543 float height = isHorizontal ? lastTextBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
1544 result = enclosingIntRect(FloatRect(x, y, width, height));
1550 LayoutRect RenderText::linesVisualOverflowBoundingBox() const
1552 if (!firstTextBox())
1553 return LayoutRect();
1555 // Return the width of the minimal left side and the maximal right side.
1556 LayoutUnit logicalLeftSide = LayoutUnit::max();
1557 LayoutUnit logicalRightSide = LayoutUnit::min();
1558 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1559 logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
1560 logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
1563 LayoutUnit logicalTop = firstTextBox()->logicalTopVisualOverflow();
1564 LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
1565 LayoutUnit logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - logicalTop;
1567 LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
1568 if (!style()->isHorizontalWritingMode())
1569 rect = rect.transposedRect();
1573 LayoutRect RenderText::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
1575 RenderObject* rendererToRepaint = containingBlock();
1577 // Do not cross self-painting layer boundaries.
1578 RenderObject* enclosingLayerRenderer = enclosingLayer()->renderer();
1579 if (enclosingLayerRenderer != rendererToRepaint && !rendererToRepaint->isDescendantOf(enclosingLayerRenderer))
1580 rendererToRepaint = enclosingLayerRenderer;
1582 // The renderer we chose to repaint may be an ancestor of repaintContainer, but we need to do a repaintContainer-relative repaint.
1583 if (repaintContainer && repaintContainer != rendererToRepaint && !rendererToRepaint->isDescendantOf(repaintContainer))
1584 return repaintContainer->clippedOverflowRectForRepaint(repaintContainer);
1586 return rendererToRepaint->clippedOverflowRectForRepaint(repaintContainer);
1589 LayoutRect RenderText::selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent)
1591 ASSERT(!needsLayout());
1593 if (selectionState() == SelectionNone)
1594 return LayoutRect();
1595 RenderBlock* cb = containingBlock();
1597 return LayoutRect();
1599 // Now calculate startPos and endPos for painting selection.
1600 // We include a selection while endPos > 0
1601 int startPos, endPos;
1602 if (selectionState() == SelectionInside) {
1603 // We are fully selected.
1605 endPos = textLength();
1607 selectionStartEnd(startPos, endPos);
1608 if (selectionState() == SelectionStart)
1609 endPos = textLength();
1610 else if (selectionState() == SelectionEnd)
1614 if (startPos == endPos)
1618 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1619 rect.unite(box->localSelectionRect(startPos, endPos));
1620 rect.unite(ellipsisRectForBox(box, startPos, endPos));
1623 if (clipToVisibleContent)
1624 computeRectForRepaint(repaintContainer, rect);
1626 if (cb->hasColumns())
1627 cb->adjustRectForColumns(rect);
1629 rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox();
1635 int RenderText::caretMinOffset() const
1637 InlineTextBox* box = firstTextBox();
1640 int minOffset = box->start();
1641 for (box = box->nextTextBox(); box; box = box->nextTextBox())
1642 minOffset = min<int>(minOffset, box->start());
1646 int RenderText::caretMaxOffset() const
1648 InlineTextBox* box = lastTextBox();
1650 return textLength();
1652 int maxOffset = box->start() + box->len();
1653 for (box = box->prevTextBox(); box; box = box->prevTextBox())
1654 maxOffset = max<int>(maxOffset, box->start() + box->len());
1658 unsigned RenderText::renderedTextLength() const
1661 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1666 int RenderText::previousOffset(int current) const
1668 if (isAllASCII() || m_text.is8Bit())
1671 StringImpl* textImpl = m_text.impl();
1672 TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
1676 long result = iterator->preceding(current);
1677 if (result == TextBreakDone)
1678 result = current - 1;
1686 #define HANGUL_CHOSEONG_START (0x1100)
1687 #define HANGUL_CHOSEONG_END (0x115F)
1688 #define HANGUL_JUNGSEONG_START (0x1160)
1689 #define HANGUL_JUNGSEONG_END (0x11A2)
1690 #define HANGUL_JONGSEONG_START (0x11A8)
1691 #define HANGUL_JONGSEONG_END (0x11F9)
1692 #define HANGUL_SYLLABLE_START (0xAC00)
1693 #define HANGUL_SYLLABLE_END (0xD7AF)
1694 #define HANGUL_JONGSEONG_COUNT (28)
1705 inline bool isHangulLVT(UChar32 character)
1707 return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
1710 inline bool isMark(UChar32 c)
1712 int8_t charType = u_charType(c);
1713 return charType == U_NON_SPACING_MARK || charType == U_ENCLOSING_MARK || charType == U_COMBINING_SPACING_MARK;
1716 inline bool isRegionalIndicator(UChar32 c)
1718 // National flag emoji each consists of a pair of regional indicator symbols.
1719 return 0x1F1E6 <= c && c <= 0x1F1FF;
1724 int RenderText::previousOffsetForBackwardDeletion(int current) const
1728 StringImpl& text = *m_text.impl();
1730 bool sawRegionalIndicator = false;
1731 while (current > 0) {
1732 if (U16_IS_TRAIL(text[--current]))
1737 UChar32 character = text.characterStartingAt(current);
1739 if (sawRegionalIndicator) {
1740 // We don't check if the pair of regional indicator symbols before current position can actually be combined
1741 // into a flag, and just delete it. This may not agree with how the pair is rendered in edge cases,
1742 // but is good enough in practice.
1743 if (isRegionalIndicator(character))
1745 // Don't delete a preceding character that isn't a regional indicator symbol.
1746 U16_FWD_1_UNSAFE(text, current);
1749 // We don't combine characters in Armenian ... Limbu range for backward deletion.
1750 if ((character >= 0x0530) && (character < 0x1950))
1753 if (isRegionalIndicator(character)) {
1754 sawRegionalIndicator = true;
1758 if (!isMark(character) && (character != 0xFF9E) && (character != 0xFF9F))
1766 character = text.characterStartingAt(current);
1767 if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) {
1770 if (character < HANGUL_JUNGSEONG_START)
1771 state = HangulStateL;
1772 else if (character < HANGUL_JONGSEONG_START)
1773 state = HangulStateV;
1774 else if (character < HANGUL_SYLLABLE_START)
1775 state = HangulStateT;
1777 state = isHangulLVT(character) ? HangulStateLVT : HangulStateLV;
1779 while (current > 0 && ((character = text.characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) {
1782 if (character <= HANGUL_CHOSEONG_END)
1783 state = HangulStateL;
1784 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END) && !isHangulLVT(character))
1785 state = HangulStateLV;
1786 else if (character > HANGUL_JUNGSEONG_END)
1787 state = HangulStateBreak;
1790 if ((character >= HANGUL_JUNGSEONG_START) && (character <= HANGUL_JUNGSEONG_END))
1791 state = HangulStateV;
1792 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))
1793 state = (isHangulLVT(character) ? HangulStateLVT : HangulStateLV);
1794 else if (character < HANGUL_JUNGSEONG_START)
1795 state = HangulStateBreak;
1798 state = (character < HANGUL_JUNGSEONG_START) ? HangulStateL : HangulStateBreak;
1801 if (state == HangulStateBreak)
1810 // Platforms other than Unix-like delete by one code point.
1811 if (U16_IS_TRAIL(m_text[--current]))
1819 int RenderText::nextOffset(int current) const
1821 if (isAllASCII() || m_text.is8Bit())
1824 StringImpl* textImpl = m_text.impl();
1825 TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
1829 long result = iterator->following(current);
1830 if (result == TextBreakDone)
1831 result = current + 1;
1836 bool RenderText::computeCanUseSimpleFontCodePath() const
1838 if (isAllASCII() || m_text.is8Bit())
1840 return Character::characterRangeCodePath(characters16(), length()) == SimplePath;
1845 void RenderText::checkConsistency() const
1847 #ifdef CHECK_CONSISTENCY
1848 const InlineTextBox* prev = 0;
1849 for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) {
1850 ASSERT(child->renderer() == this);
1851 ASSERT(child->prevTextBox() == prev);
1854 ASSERT(prev == m_lastTextBox);
1860 void RenderText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset)
1862 if (!gSecureTextTimers)
1863 gSecureTextTimers = new SecureTextTimerMap;
1865 SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this);
1866 if (!secureTextTimer) {
1867 secureTextTimer = new SecureTextTimer(this);
1868 gSecureTextTimers->add(this, secureTextTimer);
1870 secureTextTimer->restartWithNewText(lastTypedCharacterOffset);
1873 PassRefPtr<AbstractInlineTextBox> RenderText::firstAbstractInlineTextBox()
1875 return AbstractInlineTextBox::getOrCreate(this, m_firstTextBox);
1878 } // namespace WebCore