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/AlwaysInline.h>
48 #include <wtf/text/StringBuffer.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 : 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; }
90 ASSERT(gSecureTextTimers->contains(m_renderText));
91 m_renderText->setText(m_renderText->text(), 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 UChar* characters = string->characters();
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 (characters[i - 1] == noBreakSpace)
114 stringWithPrevious[i] = ' ';
116 stringWithPrevious[i] = characters[i - 1];
119 TextBreakIterator* boundary = wordBreakIterator(stringWithPrevious.characters(), length + 1);
123 StringBuffer<UChar> data(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 data[startOfWord - 1] = characters[startOfWord - 1] == noBreakSpace ? noBreakSpace : toTitleCase(stringWithPrevious[startOfWord]);
130 for (int i = startOfWord + 1; i < endOfWord; i++)
131 data[i - 1] = characters[i - 1];
134 *string = String::adopt(data);
137 RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
140 , m_linesDirty(false)
141 , m_containsReversedText(false)
142 , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
143 , m_needsTranscoding(false)
154 m_isAllASCII = m_text.containsOnlyASCII();
155 m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
158 view()->frameView()->incrementVisuallyNonEmptyCharacterCount(m_text.length());
163 RenderText::~RenderText()
165 ASSERT(!m_firstTextBox);
166 ASSERT(!m_lastTextBox);
171 const char* RenderText::renderName() const
176 bool RenderText::isTextFragment() const
181 bool RenderText::isWordBreak() const
186 void RenderText::updateNeedsTranscoding()
188 const TextEncoding* encoding = document()->decoder() ? &document()->decoder()->encoding() : 0;
189 m_needsTranscoding = fontTranscoder().needsTranscoding(style()->font().fontDescription(), encoding);
192 void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
194 // There is no need to ever schedule repaints from a style change of a text run, since
195 // we already did this for the parent of the text run.
196 // We do have to schedule layouts, though, since a style change can force us to
198 if (diff == StyleDifferenceLayout) {
199 setNeedsLayoutAndPrefWidthsRecalc();
200 m_knownToHaveNoOverflowAndNoFallbackFonts = false;
203 RenderStyle* newStyle = style();
204 bool needsResetText = false;
206 updateNeedsTranscoding();
207 needsResetText = m_needsTranscoding;
208 } else if (oldStyle->font().needsTranscoding() != newStyle->font().needsTranscoding() || (newStyle->font().needsTranscoding() && oldStyle->font().family().family() != newStyle->font().family().family())) {
209 updateNeedsTranscoding();
210 needsResetText = true;
213 ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
214 ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
215 if (needsResetText || oldTransform != newStyle->textTransform() || oldSecurity != newStyle->textSecurity())
219 void RenderText::removeAndDestroyTextBoxes()
221 if (!documentBeingDestroyed()) {
222 if (firstTextBox()) {
224 RootInlineBox* next = firstTextBox()->root()->nextRootBox();
228 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
231 parent()->dirtyLinesFromChangedChild(this);
236 void RenderText::willBeDestroyed()
238 if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->take(this) : 0)
239 delete secureTextTimer;
241 removeAndDestroyTextBoxes();
242 RenderObject::willBeDestroyed();
245 void RenderText::extractTextBox(InlineTextBox* box)
249 m_lastTextBox = box->prevTextBox();
250 if (box == m_firstTextBox)
252 if (box->prevTextBox())
253 box->prevTextBox()->setNextTextBox(0);
254 box->setPreviousTextBox(0);
255 for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox())
256 curr->setExtracted();
261 void RenderText::attachTextBox(InlineTextBox* box)
266 m_lastTextBox->setNextTextBox(box);
267 box->setPreviousTextBox(m_lastTextBox);
269 m_firstTextBox = box;
270 InlineTextBox* last = box;
271 for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {
272 curr->setExtracted(false);
275 m_lastTextBox = last;
280 void RenderText::removeTextBox(InlineTextBox* box)
284 if (box == m_firstTextBox)
285 m_firstTextBox = box->nextTextBox();
286 if (box == m_lastTextBox)
287 m_lastTextBox = box->prevTextBox();
288 if (box->nextTextBox())
289 box->nextTextBox()->setPreviousTextBox(box->prevTextBox());
290 if (box->prevTextBox())
291 box->prevTextBox()->setNextTextBox(box->nextTextBox());
296 void RenderText::deleteTextBoxes()
298 if (firstTextBox()) {
299 RenderArena* arena = renderArena();
301 for (InlineTextBox* curr = firstTextBox(); curr; curr = next) {
302 next = curr->nextTextBox();
303 curr->destroy(arena);
305 m_firstTextBox = m_lastTextBox = 0;
309 PassRefPtr<StringImpl> RenderText::originalText() const
312 return (e && e->isTextNode()) ? toText(e)->dataImpl() : 0;
315 void RenderText::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
317 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
318 rects.append(enclosingIntRect(FloatRect(accumulatedOffset + box->topLeft(), box->size())));
321 static FloatRect localQuadForTextBox(InlineTextBox* box, unsigned start, unsigned end, bool useSelectionHeight)
323 unsigned realEnd = min(box->end() + 1, end);
324 LayoutRect r = box->localSelectionRect(start, realEnd);
326 if (!useSelectionHeight) {
327 // Change the height and y position (or width and x for vertical text)
328 // because selectionRect uses selection-specific values.
329 if (box->isHorizontal()) {
330 r.setHeight(box->logicalHeight());
333 r.setWidth(box->logicalWidth());
342 void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
344 // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
345 // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
346 // function to take ints causes various internal mismatches. But selectionRect takes ints, and
347 // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
348 // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
349 ASSERT(end == UINT_MAX || end <= INT_MAX);
350 ASSERT(start <= INT_MAX);
351 start = min(start, static_cast<unsigned>(INT_MAX));
352 end = min(end, static_cast<unsigned>(INT_MAX));
354 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
355 // Note: box->end() returns the index of the last character, not the index past it
356 if (start <= box->start() && box->end() < end) {
357 FloatRect r = box->calculateBoundaries();
358 if (useSelectionHeight) {
359 LayoutRect selectionRect = box->localSelectionRect(start, end);
360 if (box->isHorizontal()) {
361 r.setHeight(selectionRect.height());
362 r.setY(selectionRect.y());
364 r.setWidth(selectionRect.width());
365 r.setX(selectionRect.x());
368 rects.append(localToAbsoluteQuad(r, false, wasFixed).enclosingBoundingBox());
370 // FIXME: This code is wrong. It's converting local to absolute twice. http://webkit.org/b/65722
371 FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
373 rects.append(localToAbsoluteQuad(rect, false, wasFixed).enclosingBoundingBox());
378 static IntRect ellipsisRectForBox(InlineTextBox* box, unsigned startPos, unsigned endPos)
383 unsigned short truncation = box->truncation();
384 if (truncation == cNoTruncation)
388 if (EllipsisBox* ellipsis = box->root()->ellipsisBox()) {
389 int ellipsisStartPosition = max<int>(startPos - box->start(), 0);
390 int ellipsisEndPosition = min<int>(endPos - box->start(), box->len());
392 // The ellipsis should be considered to be selected if the end of
393 // the selection is past the beginning of the truncation and the
394 // beginning of the selection is before or at the beginning of the truncation.
395 if (ellipsisEndPosition >= truncation && ellipsisStartPosition <= truncation)
396 return ellipsis->selectionRect();
402 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed, ClippingOption option) const
404 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
405 FloatRect boundaries = box->calculateBoundaries();
407 // Shorten the width of this text box if it ends in an ellipsis.
408 // FIXME: ellipsisRectForBox should switch to return FloatRect soon with the subpixellayout branch.
409 IntRect ellipsisRect = (option == ClipToEllipsis) ? ellipsisRectForBox(box, 0, textLength()) : IntRect();
410 if (!ellipsisRect.isEmpty()) {
411 if (style()->isHorizontalWritingMode())
412 boundaries.setWidth(ellipsisRect.maxX() - boundaries.x());
414 boundaries.setHeight(ellipsisRect.maxY() - boundaries.y());
416 quads.append(localToAbsoluteQuad(boundaries, false, wasFixed));
420 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
422 absoluteQuads(quads, wasFixed, NoClipping);
425 void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
427 // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
428 // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
429 // function to take ints causes various internal mismatches. But selectionRect takes ints, and
430 // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
431 // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
432 ASSERT(end == UINT_MAX || end <= INT_MAX);
433 ASSERT(start <= INT_MAX);
434 start = min(start, static_cast<unsigned>(INT_MAX));
435 end = min(end, static_cast<unsigned>(INT_MAX));
437 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
438 // Note: box->end() returns the index of the last character, not the index past it
439 if (start <= box->start() && box->end() < end) {
440 FloatRect r = box->calculateBoundaries();
441 if (useSelectionHeight) {
442 LayoutRect selectionRect = box->localSelectionRect(start, end);
443 if (box->isHorizontal()) {
444 r.setHeight(selectionRect.height());
445 r.setY(selectionRect.y());
447 r.setWidth(selectionRect.width());
448 r.setX(selectionRect.x());
451 quads.append(localToAbsoluteQuad(r, false, wasFixed));
453 FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
455 quads.append(localToAbsoluteQuad(rect, false, wasFixed));
460 InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const
462 // The text runs point to parts of the RenderText's m_text
463 // (they don't include '\n')
464 // Find the text run that includes the character at offset
465 // and return pos, which is the position of the char in the run.
470 InlineTextBox* s = m_firstTextBox;
472 while (offset > off && s->nextTextBox()) {
473 s = s->nextTextBox();
474 off = s->start() + s->len();
476 // we are now in the correct text run
477 pos = (offset > off ? s->len() : s->len() - (off - offset) );
481 enum ShouldAffinityBeDownstream { AlwaysDownstream, AlwaysUpstream, UpstreamIfPositionIsNotAtStart };
483 static bool lineDirectionPointFitsInBox(int pointLineDirection, InlineTextBox* box, ShouldAffinityBeDownstream& shouldAffinityBeDownstream)
485 shouldAffinityBeDownstream = AlwaysDownstream;
487 // the x coordinate is equal to the left edge of this box
488 // the affinity must be downstream so the position doesn't jump back to the previous line
489 // except when box is the first box in the line
490 if (pointLineDirection <= box->logicalLeft()) {
491 shouldAffinityBeDownstream = !box->prevLeafChild() ? UpstreamIfPositionIsNotAtStart : AlwaysDownstream;
495 // and the x coordinate is to the left of the right edge of this box
496 // check to see if position goes in this box
497 if (pointLineDirection < box->logicalRight()) {
498 shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
502 // box is first on line
503 // and the x coordinate is to the left of the first text box left edge
504 if (!box->prevLeafChildIgnoringLineBreak() && pointLineDirection < box->logicalLeft())
507 if (!box->nextLeafChildIgnoringLineBreak()) {
508 // box is last on line
509 // and the x coordinate is to the right of the last text box right edge
510 // generate VisiblePosition, use UPSTREAM affinity if possible
511 shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
518 static VisiblePosition createVisiblePositionForBox(const InlineBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
520 EAffinity affinity = VP_DEFAULT_AFFINITY;
521 switch (shouldAffinityBeDownstream) {
522 case AlwaysDownstream:
523 affinity = DOWNSTREAM;
526 affinity = VP_UPSTREAM_IF_POSSIBLE;
528 case UpstreamIfPositionIsNotAtStart:
529 affinity = offset > box->caretMinOffset() ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM;
532 return box->renderer()->createVisiblePosition(offset, affinity);
535 static VisiblePosition createVisiblePositionAfterAdjustingOffsetForBiDi(const InlineTextBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
538 ASSERT(box->renderer());
541 if (offset && static_cast<unsigned>(offset) < box->len())
542 return createVisiblePositionForBox(box, box->start() + offset, shouldAffinityBeDownstream);
544 bool positionIsAtStartOfBox = !offset;
545 if (positionIsAtStartOfBox == box->isLeftToRightDirection()) {
546 // offset is on the left edge
548 const InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak();
549 if ((prevBox && prevBox->bidiLevel() == box->bidiLevel())
550 || box->renderer()->containingBlock()->style()->direction() == box->direction()) // FIXME: left on 12CBA
551 return createVisiblePositionForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
553 if (prevBox && prevBox->bidiLevel() > box->bidiLevel()) {
554 // e.g. left of B in aDC12BAb
555 const InlineBox* leftmostBox;
557 leftmostBox = prevBox;
558 prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
559 } while (prevBox && prevBox->bidiLevel() > box->bidiLevel());
560 return createVisiblePositionForBox(leftmostBox, leftmostBox->caretRightmostOffset(), shouldAffinityBeDownstream);
563 if (!prevBox || prevBox->bidiLevel() < box->bidiLevel()) {
564 // e.g. left of D in aDC12BAb
565 const InlineBox* rightmostBox;
566 const InlineBox* nextBox = box;
568 rightmostBox = nextBox;
569 nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
570 } while (nextBox && nextBox->bidiLevel() >= box->bidiLevel());
571 return createVisiblePositionForBox(rightmostBox,
572 box->isLeftToRightDirection() ? rightmostBox->caretMaxOffset() : rightmostBox->caretMinOffset(), shouldAffinityBeDownstream);
575 return createVisiblePositionForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
578 const InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak();
579 if ((nextBox && nextBox->bidiLevel() == box->bidiLevel())
580 || box->renderer()->containingBlock()->style()->direction() == box->direction())
581 return createVisiblePositionForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
583 // offset is on the right edge
584 if (nextBox && nextBox->bidiLevel() > box->bidiLevel()) {
585 // e.g. right of C in aDC12BAb
586 const InlineBox* rightmostBox;
588 rightmostBox = nextBox;
589 nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
590 } while (nextBox && nextBox->bidiLevel() > box->bidiLevel());
591 return createVisiblePositionForBox(rightmostBox, rightmostBox->caretLeftmostOffset(), shouldAffinityBeDownstream);
594 if (!nextBox || nextBox->bidiLevel() < box->bidiLevel()) {
595 // e.g. right of A in aDC12BAb
596 const InlineBox* leftmostBox;
597 const InlineBox* prevBox = box;
599 leftmostBox = prevBox;
600 prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
601 } while (prevBox && prevBox->bidiLevel() >= box->bidiLevel());
602 return createVisiblePositionForBox(leftmostBox,
603 box->isLeftToRightDirection() ? leftmostBox->caretMinOffset() : leftmostBox->caretMaxOffset(), shouldAffinityBeDownstream);
606 return createVisiblePositionForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
609 VisiblePosition RenderText::positionForPoint(const LayoutPoint& point)
611 if (!firstTextBox() || textLength() == 0)
612 return createVisiblePosition(0, DOWNSTREAM);
614 LayoutUnit pointLineDirection = firstTextBox()->isHorizontal() ? point.x() : point.y();
615 LayoutUnit pointBlockDirection = firstTextBox()->isHorizontal() ? point.y() : point.x();
616 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
618 InlineTextBox* lastBox = 0;
619 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
620 if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild() && !box->nextLeafChild()->isLineBreak())
621 box = box->nextTextBox();
623 RootInlineBox* rootBox = box->root();
624 LayoutUnit top = min(rootBox->selectionTop(), rootBox->lineTop());
625 if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirection == top)) {
626 LayoutUnit bottom = rootBox->selectionBottom();
627 if (rootBox->nextRootBox())
628 bottom = min(bottom, rootBox->nextRootBox()->lineTop());
630 if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockDirection == bottom)) {
631 ShouldAffinityBeDownstream shouldAffinityBeDownstream;
632 if (lineDirectionPointFitsInBox(pointLineDirection, box, shouldAffinityBeDownstream))
633 return createVisiblePositionAfterAdjustingOffsetForBiDi(box, box->offsetForPosition(pointLineDirection), shouldAffinityBeDownstream);
640 ShouldAffinityBeDownstream shouldAffinityBeDownstream;
641 lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityBeDownstream);
642 return createVisiblePositionAfterAdjustingOffsetForBiDi(lastBox, lastBox->offsetForPosition(pointLineDirection) + lastBox->start(), shouldAffinityBeDownstream);
644 return createVisiblePosition(0, DOWNSTREAM);
647 LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
652 ASSERT(inlineBox->isInlineTextBox());
653 if (!inlineBox->isInlineTextBox())
656 InlineTextBox* box = toInlineTextBox(inlineBox);
658 #if ENABLE(TIZEN_SET_CARET_HEIGHT_TO_OBJECT_HEIGHT)
659 int height = box->logicalHeight();
660 int top = box->logicalTop();
662 int height = box->root()->selectionHeight();
663 int top = box->root()->selectionTop();
666 // Go ahead and round left to snap it to the nearest pixel.
667 float left = box->positionForOffset(caretOffset);
669 // Distribute the caret's width to either side of the offset.
670 int caretWidthLeftOfOffset = caretWidth / 2;
671 left -= caretWidthLeftOfOffset;
672 int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset;
676 float rootLeft = box->root()->logicalLeft();
677 float rootRight = box->root()->logicalRight();
679 // FIXME: should we use the width of the root inline box or the
680 // width of the containing block for this?
681 if (extraWidthToEndOfLine)
682 *extraWidthToEndOfLine = (box->root()->logicalWidth() + rootLeft) - (left + 1);
684 RenderBlock* cb = containingBlock();
685 RenderStyle* cbStyle = cb->style();
688 if (style()->autoWrap()) {
690 rightEdge = cb->logicalWidth();
692 leftEdge = min(static_cast<float>(0), rootLeft);
693 rightEdge = max(static_cast<float>(cb->logicalWidth()), rootRight);
696 bool rightAligned = false;
697 switch (cbStyle->textAlign()) {
709 rightAligned = !cbStyle->isLeftToRightDirection();
712 rightAligned = cbStyle->isLeftToRightDirection();
717 left = max(left, leftEdge);
718 left = min(left, rootRight - caretWidth);
720 left = min(left, rightEdge - caretWidthRightOfOffset);
721 left = max(left, rootLeft);
724 return style()->isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth);
727 ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
729 if (style()->hasTextCombine() && isCombineText()) {
730 const RenderCombineText* combineText = toRenderCombineText(this);
731 if (combineText->isCombined())
732 return combineText->combinedTextWidth(f);
735 if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
736 float monospaceCharacterWidth = f.spaceWidth();
739 bool previousCharWasSpace = true; // FIXME: Preserves historical behavior, but seems wrong for start > 0.
741 StringImpl& text = *m_text.impl();
742 for (int i = start; i < start + len; i++) {
745 if (c == ' ' || c == '\n') {
746 w += monospaceCharacterWidth;
748 } else if (c == '\t') {
749 w += style()->collapseWhiteSpace() ? monospaceCharacterWidth : f.tabWidth(style()->tabSize(), xPos + w);
754 w += monospaceCharacterWidth;
757 if (isSpace && !previousCharWasSpace)
758 w += f.wordSpacing();
759 previousCharWasSpace = isSpace;
764 TextRun run = RenderBlock::constructTextRun(const_cast<RenderText*>(this), f, text()->characters() + start, len, style());
765 run.setCharactersLength(textLength() - start);
766 ASSERT(run.charactersLength() >= run.length());
768 run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
769 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
771 return f.width(run, fallbackFonts, glyphOverflow);
774 void RenderText::trimmedPrefWidths(float leadWidth,
775 float& beginMinW, bool& beginWS,
776 float& endMinW, bool& endWS,
777 bool& hasBreakableChar, bool& hasBreak,
778 float& beginMaxW, float& endMaxW,
779 float& minW, float& maxW, bool& stripFrontSpaces)
781 bool collapseWhiteSpace = style()->collapseWhiteSpace();
782 if (!collapseWhiteSpace)
783 stripFrontSpaces = false;
785 if (m_hasTab || preferredLogicalWidthsDirty())
786 computePreferredLogicalWidths(leadWidth);
788 beginWS = !stripFrontSpaces && m_hasBeginWS;
791 int len = textLength();
793 if (!len || (stripFrontSpaces && text()->containsOnlyWhitespace())) {
807 beginMinW = m_beginMinWidth;
808 endMinW = m_endMinWidth;
810 hasBreakableChar = m_hasBreakableChar;
811 hasBreak = m_hasBreak;
814 StringImpl& text = *m_text.impl();
815 if (text[0] == ' ' || (text[0] == '\n' && !style()->preserveNewline()) || text[0] == '\t') {
816 const Font& font = style()->font(); // FIXME: This ignores first-line.
817 if (stripFrontSpaces) {
818 const UChar space = ' ';
819 float spaceWidth = font.width(RenderBlock::constructTextRun(this, font, &space, 1, style()));
822 maxW += font.wordSpacing();
825 stripFrontSpaces = collapseWhiteSpace && m_hasEndWS;
827 if (!style()->autoWrap() || minW > maxW)
830 // Compute our max widths by scanning the string for newlines.
832 const Font& f = style()->font(); // FIXME: This ignores first-line.
833 bool firstLine = true;
836 for (int i = 0; i < len; i++) {
838 while (i + linelen < len && text[i + linelen] != '\n')
842 endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW, 0, 0);
849 } else if (firstLine) {
856 // A <pre> run that ends with a newline, as in, e.g.,
857 // <pre>Some text\n\n<span>More text</pre>
863 static inline bool isSpaceAccordingToStyle(UChar c, RenderStyle* style)
865 return c == ' ' || (c == noBreakSpace && style->nbspMode() == SPACE);
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)
895 RenderStyle* style = renderer->style();
896 return font.width(RenderBlock::constructTextRun(renderer, font, style->hyphenString().string(), style));
899 static float maxWordFragmentWidth(RenderText* renderer, RenderStyle* style, const Font& font, const UChar* word, int wordLength, int minimumPrefixLength, int minimumSuffixLength, int& suffixStart)
902 if (wordLength <= minimumSuffixLength)
905 Vector<int, 8> hyphenLocations;
906 int hyphenLocation = wordLength - minimumSuffixLength;
907 while ((hyphenLocation = lastHyphenLocation(word, wordLength, hyphenLocation, style->locale())) >= minimumPrefixLength)
908 hyphenLocations.append(hyphenLocation);
910 if (hyphenLocations.isEmpty())
913 hyphenLocations.reverse();
915 float minimumFragmentWidthToConsider = font.pixelSize() * 5 / 4 + hyphenWidth(renderer, font);
916 float maxFragmentWidth = 0;
917 for (size_t k = 0; k < hyphenLocations.size(); ++k) {
918 int fragmentLength = hyphenLocations[k] - suffixStart;
919 StringBuilder fragmentWithHyphen;
920 fragmentWithHyphen.append(word + suffixStart, fragmentLength);
921 fragmentWithHyphen.append(style->hyphenString());
923 TextRun run = RenderBlock::constructTextRun(renderer, font, fragmentWithHyphen.characters(), fragmentWithHyphen.length(), style);
924 run.setCharactersLength(fragmentWithHyphen.length());
925 run.setCharacterScanForCodePath(!renderer->canUseSimpleFontCodePath());
926 float fragmentWidth = font.width(run);
928 // Narrow prefixes are ignored. See tryHyphenating in RenderBlockLineLayout.cpp.
929 if (fragmentWidth <= minimumFragmentWidthToConsider)
932 suffixStart += fragmentLength;
933 maxFragmentWidth = max(maxFragmentWidth, fragmentWidth);
936 return maxFragmentWidth;
939 void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
941 ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts);
951 float currMinWidth = 0;
952 float currMaxWidth = 0;
953 m_hasBreakableChar = false;
956 m_hasBeginWS = false;
959 RenderStyle* styleToUse = style();
960 const Font& f = styleToUse->font(); // FIXME: This ignores first-line.
961 float wordSpacing = styleToUse->wordSpacing();
962 int len = textLength();
963 const UChar* txt = characters();
964 LazyLineBreakIterator breakIterator(txt, len, styleToUse->locale());
965 bool needsWordSpacing = false;
966 bool ignoringSpaces = false;
967 bool isSpace = false;
968 bool firstWord = true;
969 bool firstLine = true;
970 int nextBreakable = -1;
971 int lastWordBoundary = 0;
973 // Non-zero only when kerning is enabled, in which case we measure words with their trailing
974 // space, then subtract its width.
975 float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(RenderBlock::constructTextRun(this, f, &space, 1, styleToUse)) : 0;
977 // If automatic hyphenation is allowed, we keep track of the width of the widest word (or word
978 // fragment) encountered so far, and only try hyphenating words that are wider.
979 float maxWordWidth = numeric_limits<float>::max();
980 int minimumPrefixLength = 0;
981 int minimumSuffixLength = 0;
982 if (styleToUse->hyphens() == HyphensAuto && canHyphenate(styleToUse->locale())) {
985 // Map 'hyphenate-limit-{before,after}: auto;' to 2.
986 minimumPrefixLength = styleToUse->hyphenationLimitBefore();
987 if (minimumPrefixLength < 0)
988 minimumPrefixLength = 2;
990 minimumSuffixLength = styleToUse->hyphenationLimitAfter();
991 if (minimumSuffixLength < 0)
992 minimumSuffixLength = 2;
995 int firstGlyphLeftOverflow = -1;
997 bool breakNBSP = styleToUse->autoWrap() && styleToUse->nbspMode() == SPACE;
998 bool breakAll = (styleToUse->wordBreak() == BreakAllWordBreak || styleToUse->wordBreak() == BreakWordBreak) && styleToUse->autoWrap();
1000 for (int i = 0; i < len; i++) {
1003 bool previousCharacterIsSpace = isSpace;
1005 bool isNewline = false;
1007 if (styleToUse->preserveNewline()) {
1013 } else if (c == '\t') {
1014 if (!styleToUse->collapseWhiteSpace()) {
1022 if ((isSpace || isNewline) && !i)
1023 m_hasBeginWS = true;
1024 if ((isSpace || isNewline) && i == len - 1)
1027 if (!ignoringSpaces && styleToUse->collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
1028 ignoringSpaces = true;
1030 if (ignoringSpaces && !isSpace)
1031 ignoringSpaces = false;
1033 // Ignore spaces and soft hyphens
1034 if (ignoringSpaces) {
1035 ASSERT(lastWordBoundary == i);
1038 } else if (c == softHyphen && styleToUse->hyphens() != HyphensNone) {
1039 currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
1040 if (firstGlyphLeftOverflow < 0)
1041 firstGlyphLeftOverflow = glyphOverflow.left;
1042 lastWordBoundary = i + 1;
1046 bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable, breakNBSP);
1047 bool betweenWords = true;
1049 while (c != '\n' && !isSpaceAccordingToStyle(c, styleToUse) && c != '\t' && (c != softHyphen || styleToUse->hyphens() == HyphensNone)) {
1054 if (isBreakable(breakIterator, j, nextBreakable, breakNBSP) && txt[j - 1] != softHyphen)
1057 betweenWords = false;
1062 int wordLen = j - i;
1064 bool isSpace = (j < len) && isSpaceAccordingToStyle(c, styleToUse);
1066 if (wordTrailingSpaceWidth && isSpace)
1067 w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth;
1069 w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
1070 if (c == softHyphen && styleToUse->hyphens() != HyphensNone)
1071 currMinWidth += hyphenWidth(this, f);
1074 if (w > maxWordWidth) {
1076 float maxFragmentWidth = maxWordFragmentWidth(this, styleToUse, f, txt + i, wordLen, minimumPrefixLength, minimumSuffixLength, suffixStart);
1080 if (wordTrailingSpaceWidth && isSpace)
1081 suffixWidth = widthFromCache(f, i + suffixStart, wordLen - suffixStart + 1, leadWidth + currMaxWidth, 0, 0) - wordTrailingSpaceWidth;
1083 suffixWidth = widthFromCache(f, i + suffixStart, wordLen - suffixStart, leadWidth + currMaxWidth, 0, 0);
1085 maxFragmentWidth = max(maxFragmentWidth, suffixWidth);
1087 currMinWidth += maxFragmentWidth - w;
1088 maxWordWidth = max(maxWordWidth, maxFragmentWidth);
1093 if (firstGlyphLeftOverflow < 0)
1094 firstGlyphLeftOverflow = glyphOverflow.left;
1097 if (lastWordBoundary == i)
1100 currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
1101 lastWordBoundary = j;
1104 bool isCollapsibleWhiteSpace = (j < len) && styleToUse->isCollapsibleWhiteSpace(c);
1105 if (j < len && styleToUse->autoWrap())
1106 m_hasBreakableChar = true;
1108 // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
1109 // last word in the run.
1110 if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
1111 currMaxWidth += wordSpacing;
1115 // If the first character in the run is breakable, then we consider ourselves to have a beginning
1116 // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
1117 // being appended to a previous text run when considering the total minimum width of the containing block.
1119 m_hasBreakableChar = true;
1120 m_beginMinWidth = hasBreak ? 0 : currMinWidth;
1122 m_endMinWidth = currMinWidth;
1124 if (currMinWidth > m_minWidth)
1125 m_minWidth = currMinWidth;
1130 // Nowrap can never be broken, so don't bother setting the
1131 // breakable character boolean. Pre can only be broken if we encounter a newline.
1132 if (style()->autoWrap() || isNewline)
1133 m_hasBreakableChar = true;
1135 if (currMinWidth > m_minWidth)
1136 m_minWidth = currMinWidth;
1139 if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
1143 if (!styleToUse->autoWrap())
1144 m_beginMinWidth = currMaxWidth;
1147 if (currMaxWidth > m_maxWidth)
1148 m_maxWidth = currMaxWidth;
1151 TextRun run = RenderBlock::constructTextRun(this, f, txt + i, 1, styleToUse);
1152 run.setCharactersLength(len - i);
1153 ASSERT(run.charactersLength() >= run.length());
1154 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
1155 run.setXPos(leadWidth + currMaxWidth);
1157 currMaxWidth += f.width(run);
1158 glyphOverflow.right = 0;
1159 needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
1161 ASSERT(lastWordBoundary == i);
1166 if (firstGlyphLeftOverflow > 0)
1167 glyphOverflow.left = firstGlyphLeftOverflow;
1169 if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord))
1170 currMaxWidth += wordSpacing;
1172 m_minWidth = max(currMinWidth, m_minWidth);
1173 m_maxWidth = max(currMaxWidth, m_maxWidth);
1175 if (!styleToUse->autoWrap())
1176 m_minWidth = m_maxWidth;
1178 if (styleToUse->whiteSpace() == PRE) {
1180 m_beginMinWidth = m_maxWidth;
1181 m_endMinWidth = currMaxWidth;
1184 setPreferredLogicalWidthsDirty(false);
1187 bool RenderText::isAllCollapsibleWhitespace()
1189 int length = textLength();
1190 const UChar* text = characters();
1191 for (int i = 0; i < length; i++) {
1192 if (!style()->isCollapsibleWhiteSpace(text[i]))
1198 bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
1201 StringImpl& text = *m_text.impl();
1203 for (currPos = from;
1204 currPos < from + len && (text[currPos] == '\n' || text[currPos] == ' ' || text[currPos] == '\t');
1206 return currPos >= (from + len);
1209 FloatPoint RenderText::firstRunOrigin() const
1211 return IntPoint(firstRunX(), firstRunY());
1214 float RenderText::firstRunX() const
1216 return m_firstTextBox ? m_firstTextBox->x() : 0;
1219 float RenderText::firstRunY() const
1221 return m_firstTextBox ? m_firstTextBox->y() : 0;
1224 void RenderText::setSelectionState(SelectionState state)
1226 RenderObject::setSelectionState(state);
1228 if (canUpdateSelectionOnRootLineBoxes()) {
1229 if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) {
1230 int startPos, endPos;
1231 selectionStartEnd(startPos, endPos);
1232 if (selectionState() == SelectionStart) {
1233 endPos = textLength();
1235 // to handle selection from end of text to end of line
1236 if (startPos && startPos == endPos)
1237 startPos = endPos - 1;
1238 } else if (selectionState() == SelectionEnd)
1241 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1242 if (box->isSelected(startPos, endPos)) {
1243 RootInlineBox* root = box->root();
1245 root->setHasSelectedChildren(true);
1249 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1250 RootInlineBox* root = box->root();
1252 root->setHasSelectedChildren(state == SelectionInside);
1257 // The containing block can be null in case of an orphaned tree.
1258 RenderBlock* containingBlock = this->containingBlock();
1259 if (containingBlock && !containingBlock->isRenderView())
1260 containingBlock->setSelectionState(state);
1263 void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force)
1265 unsigned oldLen = textLength();
1266 unsigned newLen = text->length();
1267 int delta = newLen - oldLen;
1268 unsigned end = len ? offset + len - 1 : offset;
1270 RootInlineBox* firstRootBox = 0;
1271 RootInlineBox* lastRootBox = 0;
1273 bool dirtiedLines = false;
1275 // Dirty all text boxes that include characters in between offset and offset+len.
1276 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1277 // Text run is entirely before the affected range.
1278 if (curr->end() < offset)
1281 // Text run is entirely after the affected range.
1282 if (curr->start() > end) {
1283 curr->offsetRun(delta);
1284 RootInlineBox* root = curr->root();
1285 if (!firstRootBox) {
1286 firstRootBox = root;
1287 if (!dirtiedLines) {
1288 // The affected area was in between two runs. Go ahead and mark the root box of
1289 // the run after the affected area as dirty.
1290 firstRootBox->markDirty();
1291 dirtiedLines = true;
1295 } else if (curr->end() >= offset && curr->end() <= end) {
1296 // Text run overlaps with the left end of the affected range.
1297 curr->dirtyLineBoxes();
1298 dirtiedLines = true;
1299 } else if (curr->start() <= offset && curr->end() >= end) {
1300 // Text run subsumes the affected range.
1301 curr->dirtyLineBoxes();
1302 dirtiedLines = true;
1303 } else if (curr->start() <= end && curr->end() >= end) {
1304 // Text run overlaps with right end of the affected range.
1305 curr->dirtyLineBoxes();
1306 dirtiedLines = true;
1310 // Now we have to walk all of the clean lines and adjust their cached line break information
1311 // to reflect our updated offsets.
1313 lastRootBox = lastRootBox->nextRootBox();
1315 RootInlineBox* prev = firstRootBox->prevRootBox();
1317 firstRootBox = prev;
1318 } else if (lastTextBox()) {
1319 ASSERT(!lastRootBox);
1320 firstRootBox = lastTextBox()->root();
1321 firstRootBox->markDirty();
1322 dirtiedLines = true;
1324 for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
1325 if (curr->lineBreakObj() == this && curr->lineBreakPos() > end)
1326 curr->setLineBreakPos(curr->lineBreakPos() + delta);
1329 // If the text node is empty, dirty the line where new text will be inserted.
1330 if (!firstTextBox() && parent()) {
1331 parent()->dirtyLinesFromChangedChild(this);
1332 dirtiedLines = true;
1335 m_linesDirty = dirtiedLines;
1336 setText(text, force);
1339 void RenderText::transformText()
1341 if (RefPtr<StringImpl> textToTransform = originalText())
1342 setText(textToTransform.release(), true);
1345 static inline bool isInlineFlowOrEmptyText(const RenderObject* o)
1347 if (o->isRenderInline())
1351 StringImpl* text = toRenderText(o)->text();
1354 return !text->length();
1357 UChar RenderText::previousCharacter() const
1359 // find previous text renderer if one exists
1360 const RenderObject* previousText = this;
1361 while ((previousText = previousText->previousInPreOrder()))
1362 if (!isInlineFlowOrEmptyText(previousText))
1365 if (previousText && previousText->isText())
1366 if (StringImpl* previousString = toRenderText(previousText)->text())
1367 prev = (*previousString)[previousString->length() - 1];
1371 void applyTextTransform(const RenderStyle* style, String& text, UChar previousCharacter)
1376 switch (style->textTransform()) {
1380 makeCapitalized(&text, previousCharacter);
1391 void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
1395 if (m_needsTranscoding) {
1396 const TextEncoding* encoding = document()->decoder() ? &document()->decoder()->encoding() : 0;
1397 fontTranscoder().convert(m_text, style()->font().fontDescription(), encoding);
1402 applyTextTransform(style(), m_text, previousCharacter());
1404 // We use the same characters here as for list markers.
1405 // See the listMarkerText function in RenderListMarker.cpp.
1406 switch (style()->textSecurity()) {
1410 secureText(whiteBullet);
1416 secureText(blackSquare);
1421 ASSERT(!isBR() || (textLength() == 1 && m_text[0] == '\n'));
1423 m_isAllASCII = m_text.containsOnlyASCII();
1424 m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
1427 void RenderText::secureText(UChar mask)
1429 if (!m_text.length())
1432 int lastTypedCharacterOffsetToReveal = -1;
1433 String revealedText;
1434 SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->get(this) : 0;
1435 if (secureTextTimer && secureTextTimer->isActive()) {
1436 lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOffset();
1437 if (lastTypedCharacterOffsetToReveal >= 0)
1438 revealedText.append(m_text[lastTypedCharacterOffsetToReveal]);
1442 if (lastTypedCharacterOffsetToReveal >= 0) {
1443 m_text.replace(lastTypedCharacterOffsetToReveal, 1, revealedText);
1444 // m_text may be updated later before timer fires. We invalidate the lastTypedCharacterOffset to avoid inconsistency.
1445 secureTextTimer->invalidate();
1449 void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
1453 if (!force && equal(m_text.impl(), text.get()))
1456 setTextInternal(text);
1457 setNeedsLayoutAndPrefWidthsRecalc();
1458 m_knownToHaveNoOverflowAndNoFallbackFonts = false;
1460 AXObjectCache* axObjectCache = document()->axObjectCache();
1461 if (axObjectCache->accessibilityEnabled())
1462 axObjectCache->contentChanged(this);
1465 String RenderText::textWithoutTranscoding() const
1467 // If m_text isn't transcoded or is secure, we can just return the modified text.
1468 if (!m_needsTranscoding || style()->textSecurity() != TSNONE)
1471 // Otherwise, we should use original text. If text-transform is
1472 // specified, we should transform the text on the fly.
1473 String text = originalText();
1474 applyTextTransform(style(), text, previousCharacter());
1478 void RenderText::dirtyLineBoxes(bool fullLayout)
1482 else if (!m_linesDirty) {
1483 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1484 box->dirtyLineBoxes();
1486 m_linesDirty = false;
1489 InlineTextBox* RenderText::createTextBox()
1491 return new (renderArena()) InlineTextBox(this);
1494 InlineTextBox* RenderText::createInlineTextBox()
1496 InlineTextBox* textBox = createTextBox();
1497 if (!m_firstTextBox)
1498 m_firstTextBox = m_lastTextBox = textBox;
1500 m_lastTextBox->setNextTextBox(textBox);
1501 textBox->setPreviousTextBox(m_lastTextBox);
1502 m_lastTextBox = textBox;
1504 textBox->setIsText(true);
1508 void RenderText::positionLineBox(InlineBox* box)
1510 InlineTextBox* s = toInlineTextBox(box);
1512 // FIXME: should not be needed!!!
1514 // We want the box to be destroyed.
1516 if (m_firstTextBox == s)
1517 m_firstTextBox = s->nextTextBox();
1519 s->prevTextBox()->setNextTextBox(s->nextTextBox());
1520 if (m_lastTextBox == s)
1521 m_lastTextBox = s->prevTextBox();
1523 s->nextTextBox()->setPreviousTextBox(s->prevTextBox());
1524 s->destroy(renderArena());
1528 m_containsReversedText |= !s->isLeftToRightDirection();
1531 float RenderText::width(unsigned from, unsigned len, float xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1533 if (from >= textLength())
1536 if (from + len > textLength())
1537 len = textLength() - from;
1539 return width(from, len, style(firstLine)->font(), xPos, fallbackFonts, glyphOverflow);
1542 float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1544 ASSERT(from + len <= textLength());
1549 if (&f == &style()->font()) {
1550 if (!style()->preserveNewline() && !from && len == textLength() && (!glyphOverflow || !glyphOverflow->computeBounds)) {
1551 if (fallbackFonts) {
1552 ASSERT(glyphOverflow);
1553 if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
1554 const_cast<RenderText*>(this)->computePreferredLogicalWidths(0, *fallbackFonts, *glyphOverflow);
1555 if (fallbackFonts->isEmpty() && !glyphOverflow->left && !glyphOverflow->right && !glyphOverflow->top && !glyphOverflow->bottom)
1556 m_knownToHaveNoOverflowAndNoFallbackFonts = true;
1560 w = maxLogicalWidth();
1562 w = widthFromCache(f, from, len, xPos, fallbackFonts, glyphOverflow);
1564 TextRun run = RenderBlock::constructTextRun(const_cast<RenderText*>(this), f, text()->characters() + from, len, style());
1565 run.setCharactersLength(textLength() - from);
1566 ASSERT(run.charactersLength() >= run.length());
1568 run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
1569 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
1571 w = f.width(run, fallbackFonts, glyphOverflow);
1577 IntRect RenderText::linesBoundingBox() const
1581 ASSERT(!firstTextBox() == !lastTextBox()); // Either both are null or both exist.
1582 if (firstTextBox() && lastTextBox()) {
1583 // Return the width of the minimal left side and the maximal right side.
1584 float logicalLeftSide = 0;
1585 float logicalRightSide = 0;
1586 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1587 if (curr == firstTextBox() || curr->logicalLeft() < logicalLeftSide)
1588 logicalLeftSide = curr->logicalLeft();
1589 if (curr == firstTextBox() || curr->logicalRight() > logicalRightSide)
1590 logicalRightSide = curr->logicalRight();
1593 bool isHorizontal = style()->isHorizontalWritingMode();
1595 float x = isHorizontal ? logicalLeftSide : firstTextBox()->x();
1596 float y = isHorizontal ? firstTextBox()->y() : logicalLeftSide;
1597 float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTextBox()->logicalBottom() - x;
1598 float height = isHorizontal ? lastTextBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
1599 result = enclosingIntRect(FloatRect(x, y, width, height));
1605 LayoutRect RenderText::linesVisualOverflowBoundingBox() const
1607 if (!firstTextBox())
1608 return LayoutRect();
1610 // Return the width of the minimal left side and the maximal right side.
1611 LayoutUnit logicalLeftSide = MAX_LAYOUT_UNIT;
1612 LayoutUnit logicalRightSide = MIN_LAYOUT_UNIT;
1613 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
1614 logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
1615 logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
1618 LayoutUnit logicalTop = firstTextBox()->logicalTopVisualOverflow();
1619 LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
1620 LayoutUnit logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - logicalTop;
1622 LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
1623 if (!style()->isHorizontalWritingMode())
1624 rect = rect.transposedRect();
1628 LayoutRect RenderText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const
1630 RenderObject* rendererToRepaint = containingBlock();
1632 // Do not cross self-painting layer boundaries.
1633 RenderObject* enclosingLayerRenderer = enclosingLayer()->renderer();
1634 if (enclosingLayerRenderer != rendererToRepaint && !rendererToRepaint->isDescendantOf(enclosingLayerRenderer))
1635 rendererToRepaint = enclosingLayerRenderer;
1637 // The renderer we chose to repaint may be an ancestor of repaintContainer, but we need to do a repaintContainer-relative repaint.
1638 if (repaintContainer && repaintContainer != rendererToRepaint && !rendererToRepaint->isDescendantOf(repaintContainer))
1639 return repaintContainer->clippedOverflowRectForRepaint(repaintContainer);
1641 return rendererToRepaint->clippedOverflowRectForRepaint(repaintContainer);
1644 LayoutRect RenderText::selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent)
1646 ASSERT(!needsLayout());
1648 if (selectionState() == SelectionNone)
1649 return LayoutRect();
1650 RenderBlock* cb = containingBlock();
1652 return LayoutRect();
1654 // Now calculate startPos and endPos for painting selection.
1655 // We include a selection while endPos > 0
1656 int startPos, endPos;
1657 if (selectionState() == SelectionInside) {
1658 // We are fully selected.
1660 endPos = textLength();
1662 selectionStartEnd(startPos, endPos);
1663 if (selectionState() == SelectionStart)
1664 endPos = textLength();
1665 else if (selectionState() == SelectionEnd)
1669 if (startPos == endPos)
1673 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
1674 rect.unite(box->localSelectionRect(startPos, endPos));
1675 rect.unite(ellipsisRectForBox(box, startPos, endPos));
1678 if (clipToVisibleContent)
1679 computeRectForRepaint(repaintContainer, rect);
1681 if (cb->hasColumns())
1682 cb->adjustRectForColumns(rect);
1684 rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox();
1690 int RenderText::caretMinOffset() const
1692 InlineTextBox* box = firstTextBox();
1695 int minOffset = box->start();
1696 for (box = box->nextTextBox(); box; box = box->nextTextBox())
1697 minOffset = min<int>(minOffset, box->start());
1701 int RenderText::caretMaxOffset() const
1703 InlineTextBox* box = lastTextBox();
1705 return textLength();
1707 int maxOffset = box->start() + box->len();
1708 for (box = box->prevTextBox(); box; box = box->prevTextBox())
1709 maxOffset = max<int>(maxOffset, box->start() + box->len());
1713 unsigned RenderText::renderedTextLength() const
1716 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
1721 int RenderText::previousOffset(int current) const
1723 StringImpl* si = m_text.impl();
1724 TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length());
1728 long result = textBreakPreceding(iterator, current);
1729 if (result == TextBreakDone)
1730 result = current - 1;
1736 #if PLATFORM(MAC) || PLATFORM(CHROMIUM) && OS(MAC_OS_X)
1738 #define HANGUL_CHOSEONG_START (0x1100)
1739 #define HANGUL_CHOSEONG_END (0x115F)
1740 #define HANGUL_JUNGSEONG_START (0x1160)
1741 #define HANGUL_JUNGSEONG_END (0x11A2)
1742 #define HANGUL_JONGSEONG_START (0x11A8)
1743 #define HANGUL_JONGSEONG_END (0x11F9)
1744 #define HANGUL_SYLLABLE_START (0xAC00)
1745 #define HANGUL_SYLLABLE_END (0xD7AF)
1746 #define HANGUL_JONGSEONG_COUNT (28)
1757 inline bool isHangulLVT(UChar32 character)
1759 return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
1762 inline bool isMark(UChar32 c)
1764 int8_t charType = u_charType(c);
1765 return charType == U_NON_SPACING_MARK || charType == U_ENCLOSING_MARK || charType == U_COMBINING_SPACING_MARK;
1768 inline bool isRegionalIndicator(UChar32 c)
1770 // National flag emoji each consists of a pair of regional indicator symbols.
1771 return 0x1F1E6 <= c && c <= 0x1F1FF;
1776 int RenderText::previousOffsetForBackwardDeletion(int current) const
1778 #if PLATFORM(MAC) || PLATFORM(CHROMIUM) && OS(MAC_OS_X)
1780 StringImpl& text = *m_text.impl();
1782 bool sawRegionalIndicator = false;
1783 while (current > 0) {
1784 if (U16_IS_TRAIL(text[--current]))
1789 UChar32 character = text.characterStartingAt(current);
1791 if (sawRegionalIndicator) {
1792 // We don't check if the pair of regional indicator symbols before current position can actually be combined
1793 // into a flag, and just delete it. This may not agree with how the pair is rendered in edge cases,
1794 // but is good enough in practice.
1795 if (isRegionalIndicator(character))
1797 // Don't delete a preceding character that isn't a regional indicator symbol.
1798 U16_FWD_1_UNSAFE(text, current);
1801 // We don't combine characters in Armenian ... Limbu range for backward deletion.
1802 if ((character >= 0x0530) && (character < 0x1950))
1805 if (isRegionalIndicator(character)) {
1806 sawRegionalIndicator = true;
1810 if (!isMark(character) && (character != 0xFF9E) && (character != 0xFF9F))
1818 character = text.characterStartingAt(current);
1819 if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) {
1821 HangulState initialState;
1823 if (character < HANGUL_JUNGSEONG_START)
1824 state = HangulStateL;
1825 else if (character < HANGUL_JONGSEONG_START)
1826 state = HangulStateV;
1827 else if (character < HANGUL_SYLLABLE_START)
1828 state = HangulStateT;
1830 state = isHangulLVT(character) ? HangulStateLVT : HangulStateLV;
1832 initialState = state;
1834 while (current > 0 && ((character = text.characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) {
1837 if (character <= HANGUL_CHOSEONG_END)
1838 state = HangulStateL;
1839 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END) && !isHangulLVT(character))
1840 state = HangulStateLV;
1841 else if (character > HANGUL_JUNGSEONG_END)
1842 state = HangulStateBreak;
1845 if ((character >= HANGUL_JUNGSEONG_START) && (character <= HANGUL_JUNGSEONG_END))
1846 state = HangulStateV;
1847 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))
1848 state = (isHangulLVT(character) ? HangulStateLVT : HangulStateLV);
1849 else if (character < HANGUL_JUNGSEONG_START)
1850 state = HangulStateBreak;
1853 state = (character < HANGUL_JUNGSEONG_START) ? HangulStateL : HangulStateBreak;
1856 if (state == HangulStateBreak)
1865 // Platforms other than Mac delete by one code point.
1866 if (U16_IS_TRAIL(m_text[--current]))
1874 int RenderText::nextOffset(int current) const
1876 StringImpl* si = m_text.impl();
1877 TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length());
1881 long result = textBreakFollowing(iterator, current);
1882 if (result == TextBreakDone)
1883 result = current + 1;
1889 bool RenderText::computeCanUseSimpleFontCodePath() const
1893 return Font::characterRangeCodePath(characters(), length()) == Font::Simple;
1898 void RenderText::checkConsistency() const
1900 #ifdef CHECK_CONSISTENCY
1901 const InlineTextBox* prev = 0;
1902 for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) {
1903 ASSERT(child->renderer() == this);
1904 ASSERT(child->prevTextBox() == prev);
1907 ASSERT(prev == m_lastTextBox);
1913 void RenderText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset)
1915 if (!gSecureTextTimers)
1916 gSecureTextTimers = new SecureTextTimerMap;
1918 SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this);
1919 if (!secureTextTimer) {
1920 secureTextTimer = new SecureTextTimer(this);
1921 gSecureTextTimers->add(this, secureTextTimer);
1923 secureTextTimer->restartWithNewText(lastTypedCharacterOffset);
1926 } // namespace WebCore