Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1489)

Unified Diff: Source/core/rendering/RenderText.cpp

Issue 940373003: Rename RenderText to LayoutText (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/rendering/RenderText.h ('k') | Source/core/rendering/RenderTextFragment.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/rendering/RenderText.cpp
diff --git a/Source/core/rendering/RenderText.cpp b/Source/core/rendering/RenderText.cpp
deleted file mode 100644
index a959e3983fd81a5979aa4c051ee7298880a1d736..0000000000000000000000000000000000000000
--- a/Source/core/rendering/RenderText.cpp
+++ /dev/null
@@ -1,1899 +0,0 @@
-/*
- * (C) 1999 Lars Knoll (knoll@kde.org)
- * (C) 2000 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
- * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "core/rendering/RenderText.h"
-
-#include "core/dom/AXObjectCache.h"
-#include "core/dom/Text.h"
-#include "core/editing/VisiblePosition.h"
-#include "core/editing/iterators/TextIterator.h"
-#include "core/frame/FrameView.h"
-#include "core/frame/Settings.h"
-#include "core/html/parser/TextResourceDecoder.h"
-#include "core/layout/Layer.h"
-#include "core/layout/LayoutBlock.h"
-#include "core/layout/LayoutView.h"
-#include "core/layout/TextRunConstructor.h"
-#include "core/layout/line/AbstractInlineTextBox.h"
-#include "core/layout/line/EllipsisBox.h"
-#include "core/layout/line/InlineTextBox.h"
-#include "core/rendering/RenderCombineText.h"
-#include "platform/fonts/Character.h"
-#include "platform/fonts/FontCache.h"
-#include "platform/geometry/FloatQuad.h"
-#include "platform/graphics/paint/DisplayItemList.h"
-#include "platform/text/BidiResolver.h"
-#include "platform/text/TextBreakIterator.h"
-#include "platform/text/TextRunIterator.h"
-#include "wtf/text/StringBuffer.h"
-#include "wtf/text/StringBuilder.h"
-#include "wtf/unicode/CharacterNames.h"
-
-using namespace WTF;
-using namespace Unicode;
-
-namespace blink {
-
-struct SameSizeAsRenderText : public LayoutObject {
- uint32_t bitfields : 16;
- float widths[4];
- String text;
- void* pointers[2];
-};
-
-static_assert(sizeof(RenderText) == sizeof(SameSizeAsRenderText), "RenderText should stay small");
-
-class SecureTextTimer;
-typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap;
-static SecureTextTimerMap* gSecureTextTimers = 0;
-
-class SecureTextTimer final : public TimerBase {
-public:
- SecureTextTimer(RenderText* renderText)
- : m_renderText(renderText)
- , m_lastTypedCharacterOffset(-1)
- {
- }
-
- void restartWithNewText(unsigned lastTypedCharacterOffset)
- {
- m_lastTypedCharacterOffset = lastTypedCharacterOffset;
- if (Settings* settings = m_renderText->document().settings())
- startOneShot(settings->passwordEchoDurationInSeconds(), FROM_HERE);
- }
- void invalidate() { m_lastTypedCharacterOffset = -1; }
- unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; }
-
-private:
- virtual void fired() override
- {
- ASSERT(gSecureTextTimers->contains(m_renderText));
- m_renderText->setText(m_renderText->text().impl(), true /* forcing setting text as it may be masked later */);
- }
-
- RenderText* m_renderText;
- int m_lastTypedCharacterOffset;
-};
-
-static void makeCapitalized(String* string, UChar previous)
-{
- if (string->isNull())
- return;
-
- unsigned length = string->length();
- const StringImpl& input = *string->impl();
-
- if (length >= std::numeric_limits<unsigned>::max())
- CRASH();
-
- StringBuffer<UChar> stringWithPrevious(length + 1);
- stringWithPrevious[0] = previous == noBreakSpace ? space : previous;
- for (unsigned i = 1; i < length + 1; i++) {
- // Replace &nbsp with a real space since ICU no longer treats &nbsp as a word separator.
- if (input[i - 1] == noBreakSpace)
- stringWithPrevious[i] = space;
- else
- stringWithPrevious[i] = input[i - 1];
- }
-
- TextBreakIterator* boundary = wordBreakIterator(stringWithPrevious.characters(), length + 1);
- if (!boundary)
- return;
-
- StringBuilder result;
- result.reserveCapacity(length);
-
- int32_t endOfWord;
- int32_t startOfWord = boundary->first();
- for (endOfWord = boundary->next(); endOfWord != TextBreakDone; startOfWord = endOfWord, endOfWord = boundary->next()) {
- if (startOfWord) // Ignore first char of previous string
- result.append(input[startOfWord - 1] == noBreakSpace ? noBreakSpace : toTitleCase(stringWithPrevious[startOfWord]));
- for (int i = startOfWord + 1; i < endOfWord; i++)
- result.append(input[i - 1]);
- }
-
- *string = result.toString();
-}
-
-RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
- : LayoutObject(!node || node->isDocumentNode() ? 0 : node)
- , m_hasTab(false)
- , m_linesDirty(false)
- , m_containsReversedText(false)
- , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
- , m_minWidth(-1)
- , m_maxWidth(-1)
- , m_firstLineMinWidth(0)
- , m_lastLineLineMinWidth(0)
- , m_text(str)
- , m_firstTextBox(0)
- , m_lastTextBox(0)
-{
- ASSERT(m_text);
- // FIXME: Some clients of RenderText (and subclasses) pass Document as node to create anonymous renderer.
- // They should be switched to passing null and using setDocumentForAnonymous.
- if (node && node->isDocumentNode())
- setDocumentForAnonymous(toDocument(node));
-
- m_isAllASCII = m_text.containsOnlyASCII();
- m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
- setIsText();
-
- view()->frameView()->incrementVisuallyNonEmptyCharacterCount(m_text.length());
-}
-
-#if ENABLE(ASSERT)
-
-RenderText::~RenderText()
-{
- ASSERT(!m_firstTextBox);
- ASSERT(!m_lastTextBox);
-}
-
-#endif
-
-const char* RenderText::renderName() const
-{
- return "RenderText";
-}
-
-bool RenderText::isTextFragment() const
-{
- return false;
-}
-
-bool RenderText::isWordBreak() const
-{
- return false;
-}
-
-void RenderText::styleDidChange(StyleDifference diff, const LayoutStyle* oldStyle)
-{
- // There is no need to ever schedule paint invalidations from a style change of a text run, since
- // we already did this for the parent of the text run.
- // We do have to schedule layouts, though, since a style change can force us to
- // need to relayout.
- if (diff.needsFullLayout()) {
- setNeedsLayoutAndPrefWidthsRecalc();
- m_knownToHaveNoOverflowAndNoFallbackFonts = false;
- }
-
- const LayoutStyle& newStyle = styleRef();
- ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
- ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
- if (oldTransform != newStyle.textTransform() || oldSecurity != newStyle.textSecurity())
- transformText();
-
- // This is an optimization that kicks off font load before layout.
- // In order to make it fast, we only check if the first character of the
- // text is included in the unicode ranges of the fonts.
- if (!text().containsOnlyWhitespace())
- newStyle.font().willUseFontData(text().characterStartingAt(0));
-}
-
-void RenderText::removeAndDestroyTextBoxes()
-{
- if (!documentBeingDestroyed()) {
- if (firstTextBox()) {
- if (isBR()) {
- RootInlineBox* next = firstTextBox()->root().nextRootBox();
- if (next)
- next->markDirty();
- }
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- box->remove();
- } else if (parent())
- parent()->dirtyLinesFromChangedChild(this);
- }
- deleteTextBoxes();
-}
-
-void RenderText::willBeDestroyed()
-{
- if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->take(this) : 0)
- delete secureTextTimer;
-
- removeAndDestroyTextBoxes();
- LayoutObject::willBeDestroyed();
-}
-
-void RenderText::extractTextBox(InlineTextBox* box)
-{
- checkConsistency();
-
- m_lastTextBox = box->prevTextBox();
- if (box == m_firstTextBox)
- m_firstTextBox = 0;
- if (box->prevTextBox())
- box->prevTextBox()->setNextTextBox(0);
- box->setPreviousTextBox(0);
- for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox())
- curr->setExtracted();
-
- checkConsistency();
-}
-
-void RenderText::attachTextBox(InlineTextBox* box)
-{
- checkConsistency();
-
- if (m_lastTextBox) {
- m_lastTextBox->setNextTextBox(box);
- box->setPreviousTextBox(m_lastTextBox);
- } else
- m_firstTextBox = box;
- InlineTextBox* last = box;
- for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {
- curr->setExtracted(false);
- last = curr;
- }
- m_lastTextBox = last;
-
- checkConsistency();
-}
-
-void RenderText::removeTextBox(InlineTextBox* box)
-{
- checkConsistency();
-
- if (box == m_firstTextBox)
- m_firstTextBox = box->nextTextBox();
- if (box == m_lastTextBox)
- m_lastTextBox = box->prevTextBox();
- if (box->nextTextBox())
- box->nextTextBox()->setPreviousTextBox(box->prevTextBox());
- if (box->prevTextBox())
- box->prevTextBox()->setNextTextBox(box->nextTextBox());
-
- checkConsistency();
-}
-
-void RenderText::deleteTextBoxes()
-{
- if (firstTextBox()) {
- InlineTextBox* next;
- for (InlineTextBox* curr = firstTextBox(); curr; curr = next) {
- next = curr->nextTextBox();
- curr->destroy();
- }
- m_firstTextBox = m_lastTextBox = 0;
- }
-}
-
-PassRefPtr<StringImpl> RenderText::originalText() const
-{
- Node* e = node();
- return (e && e->isTextNode()) ? toText(e)->dataImpl() : 0;
-}
-
-String RenderText::plainText() const
-{
- if (node())
- return blink::plainText(rangeOfContents(node()).get());
-
- // FIXME: this is just a stopgap until TextIterator is adapted to support generated text.
- StringBuilder plainTextBuilder;
- for (InlineTextBox* textBox = firstTextBox(); textBox; textBox = textBox->nextTextBox()) {
- String text = m_text.substring(textBox->start(), textBox->len()).simplifyWhiteSpace(WTF::DoNotStripWhiteSpace);
- plainTextBuilder.append(text);
- if (textBox->nextTextBox() && textBox->nextTextBox()->start() > textBox->end() && text.length() && !text.right(1).containsOnlyWhitespace())
- plainTextBuilder.append(space);
- }
- return plainTextBuilder.toString();
-}
-
-void RenderText::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
-{
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- rects.append(enclosingIntRect(FloatRect(FloatPoint(accumulatedOffset) + box->topLeft().toFloatPoint(), box->size().toFloatSize())));
-}
-
-static FloatRect localQuadForTextBox(InlineTextBox* box, unsigned start, unsigned end, bool useSelectionHeight)
-{
- unsigned realEnd = std::min(box->end() + 1, end);
- LayoutRect r = box->localSelectionRect(start, realEnd);
- if (r.height()) {
- if (!useSelectionHeight) {
- // Change the height and y position (or width and x for vertical text)
- // because selectionRect uses selection-specific values.
- if (box->isHorizontal()) {
- r.setHeight(box->height());
- r.setY(box->y());
- } else {
- r.setWidth(box->width());
- r.setX(box->x());
- }
- }
- return FloatRect(r);
- }
- return FloatRect();
-}
-
-void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
-{
- // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
- // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
- // function to take ints causes various internal mismatches. But selectionRect takes ints, and
- // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
- // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
- ASSERT(end == UINT_MAX || end <= INT_MAX);
- ASSERT(start <= INT_MAX);
- start = std::min(start, static_cast<unsigned>(INT_MAX));
- end = std::min(end, static_cast<unsigned>(INT_MAX));
-
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- // Note: box->end() returns the index of the last character, not the index past it
- if (start <= box->start() && box->end() < end) {
- FloatRect r = box->calculateBoundaries().toFloatRect();
- if (useSelectionHeight) {
- LayoutRect selectionRect = box->localSelectionRect(start, end);
- if (box->isHorizontal()) {
- r.setHeight(selectionRect.height().toFloat());
- r.setY(selectionRect.y().toFloat());
- } else {
- r.setWidth(selectionRect.width().toFloat());
- r.setX(selectionRect.x().toFloat());
- }
- }
- rects.append(localToAbsoluteQuad(r, 0, wasFixed).enclosingBoundingBox());
- } else {
- // FIXME: This code is wrong. It's converting local to absolute twice. http://webkit.org/b/65722
- FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
- if (!rect.isZero())
- rects.append(localToAbsoluteQuad(rect, 0, wasFixed).enclosingBoundingBox());
- }
- }
-}
-
-static IntRect ellipsisRectForBox(InlineTextBox* box, unsigned startPos, unsigned endPos)
-{
- if (!box)
- return IntRect();
-
- unsigned short truncation = box->truncation();
- if (truncation == cNoTruncation)
- return IntRect();
-
- IntRect rect;
- if (EllipsisBox* ellipsis = box->root().ellipsisBox()) {
- int ellipsisStartPosition = std::max<int>(startPos - box->start(), 0);
- int ellipsisEndPosition = std::min<int>(endPos - box->start(), box->len());
-
- // The ellipsis should be considered to be selected if the end of
- // the selection is past the beginning of the truncation and the
- // beginning of the selection is before or at the beginning of the truncation.
- if (ellipsisEndPosition >= truncation && ellipsisStartPosition <= truncation)
- return ellipsis->selectionRect();
- }
-
- return IntRect();
-}
-
-void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed, ClippingOption option) const
-{
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- FloatRect boundaries = box->calculateBoundaries().toFloatRect();
-
- // Shorten the width of this text box if it ends in an ellipsis.
- // FIXME: ellipsisRectForBox should switch to return FloatRect soon with the subpixellayout branch.
- IntRect ellipsisRect = (option == ClipToEllipsis) ? ellipsisRectForBox(box, 0, textLength()) : IntRect();
- if (!ellipsisRect.isEmpty()) {
- if (style()->isHorizontalWritingMode())
- boundaries.setWidth(ellipsisRect.maxX() - boundaries.x());
- else
- boundaries.setHeight(ellipsisRect.maxY() - boundaries.y());
- }
- quads.append(localToAbsoluteQuad(boundaries, 0, wasFixed));
- }
-}
-
-void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
-{
- absoluteQuads(quads, wasFixed, NoClipping);
-}
-
-void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed)
-{
- // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
- // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
- // function to take ints causes various internal mismatches. But selectionRect takes ints, and
- // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
- // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
- ASSERT(end == UINT_MAX || end <= INT_MAX);
- ASSERT(start <= INT_MAX);
- start = std::min(start, static_cast<unsigned>(INT_MAX));
- end = std::min(end, static_cast<unsigned>(INT_MAX));
-
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- // Note: box->end() returns the index of the last character, not the index past it
- if (start <= box->start() && box->end() < end) {
- FloatRect r = box->calculateBoundaries().toFloatRect();
- if (useSelectionHeight) {
- LayoutRect selectionRect = box->localSelectionRect(start, end);
- if (box->isHorizontal()) {
- r.setHeight(selectionRect.height().toFloat());
- r.setY(selectionRect.y().toFloat());
- } else {
- r.setWidth(selectionRect.width().toFloat());
- r.setX(selectionRect.x().toFloat());
- }
- }
- quads.append(localToAbsoluteQuad(r, 0, wasFixed));
- } else {
- FloatRect rect = localQuadForTextBox(box, start, end, useSelectionHeight);
- if (!rect.isZero())
- quads.append(localToAbsoluteQuad(rect, 0, wasFixed));
- }
- }
-}
-
-enum ShouldAffinityBeDownstream { AlwaysDownstream, AlwaysUpstream, UpstreamIfPositionIsNotAtStart };
-
-static bool lineDirectionPointFitsInBox(int pointLineDirection, InlineTextBox* box, ShouldAffinityBeDownstream& shouldAffinityBeDownstream)
-{
- shouldAffinityBeDownstream = AlwaysDownstream;
-
- // the x coordinate is equal to the left edge of this box
- // the affinity must be downstream so the position doesn't jump back to the previous line
- // except when box is the first box in the line
- if (pointLineDirection <= box->logicalLeft()) {
- shouldAffinityBeDownstream = !box->prevLeafChild() ? UpstreamIfPositionIsNotAtStart : AlwaysDownstream;
- return true;
- }
-
- // and the x coordinate is to the left of the right edge of this box
- // check to see if position goes in this box
- if (pointLineDirection < box->logicalRight()) {
- shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
- return true;
- }
-
- // box is first on line
- // and the x coordinate is to the left of the first text box left edge
- if (!box->prevLeafChildIgnoringLineBreak() && pointLineDirection < box->logicalLeft())
- return true;
-
- if (!box->nextLeafChildIgnoringLineBreak()) {
- // box is last on line
- // and the x coordinate is to the right of the last text box right edge
- // generate VisiblePosition, use UPSTREAM affinity if possible
- shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
- return true;
- }
-
- return false;
-}
-
-static PositionWithAffinity createPositionWithAffinityForBox(const InlineBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
-{
- EAffinity affinity = VP_DEFAULT_AFFINITY;
- switch (shouldAffinityBeDownstream) {
- case AlwaysDownstream:
- affinity = DOWNSTREAM;
- break;
- case AlwaysUpstream:
- affinity = VP_UPSTREAM_IF_POSSIBLE;
- break;
- case UpstreamIfPositionIsNotAtStart:
- affinity = offset > box->caretMinOffset() ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM;
- break;
- }
- int textStartOffset = box->renderer().isText() ? toRenderText(box->renderer()).textStartOffset() : 0;
- return box->renderer().createPositionWithAffinity(offset + textStartOffset, affinity);
-}
-
-static PositionWithAffinity createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(const InlineTextBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
-{
- ASSERT(box);
- ASSERT(offset >= 0);
-
- if (offset && static_cast<unsigned>(offset) < box->len())
- return createPositionWithAffinityForBox(box, box->start() + offset, shouldAffinityBeDownstream);
-
- bool positionIsAtStartOfBox = !offset;
- if (positionIsAtStartOfBox == box->isLeftToRightDirection()) {
- // offset is on the left edge
-
- const InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak();
- if ((prevBox && prevBox->bidiLevel() == box->bidiLevel())
- || box->renderer().containingBlock()->style()->direction() == box->direction()) // FIXME: left on 12CBA
- return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
-
- if (prevBox && prevBox->bidiLevel() > box->bidiLevel()) {
- // e.g. left of B in aDC12BAb
- const InlineBox* leftmostBox;
- do {
- leftmostBox = prevBox;
- prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
- } while (prevBox && prevBox->bidiLevel() > box->bidiLevel());
- return createPositionWithAffinityForBox(leftmostBox, leftmostBox->caretRightmostOffset(), shouldAffinityBeDownstream);
- }
-
- if (!prevBox || prevBox->bidiLevel() < box->bidiLevel()) {
- // e.g. left of D in aDC12BAb
- const InlineBox* rightmostBox;
- const InlineBox* nextBox = box;
- do {
- rightmostBox = nextBox;
- nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
- } while (nextBox && nextBox->bidiLevel() >= box->bidiLevel());
- return createPositionWithAffinityForBox(rightmostBox,
- box->isLeftToRightDirection() ? rightmostBox->caretMaxOffset() : rightmostBox->caretMinOffset(), shouldAffinityBeDownstream);
- }
-
- return createPositionWithAffinityForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
- }
-
- const InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak();
- if ((nextBox && nextBox->bidiLevel() == box->bidiLevel())
- || box->renderer().containingBlock()->style()->direction() == box->direction())
- return createPositionWithAffinityForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
-
- // offset is on the right edge
- if (nextBox && nextBox->bidiLevel() > box->bidiLevel()) {
- // e.g. right of C in aDC12BAb
- const InlineBox* rightmostBox;
- do {
- rightmostBox = nextBox;
- nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
- } while (nextBox && nextBox->bidiLevel() > box->bidiLevel());
- return createPositionWithAffinityForBox(rightmostBox, rightmostBox->caretLeftmostOffset(), shouldAffinityBeDownstream);
- }
-
- if (!nextBox || nextBox->bidiLevel() < box->bidiLevel()) {
- // e.g. right of A in aDC12BAb
- const InlineBox* leftmostBox;
- const InlineBox* prevBox = box;
- do {
- leftmostBox = prevBox;
- prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
- } while (prevBox && prevBox->bidiLevel() >= box->bidiLevel());
- return createPositionWithAffinityForBox(leftmostBox,
- box->isLeftToRightDirection() ? leftmostBox->caretMinOffset() : leftmostBox->caretMaxOffset(), shouldAffinityBeDownstream);
- }
-
- return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
-}
-
-PositionWithAffinity RenderText::positionForPoint(const LayoutPoint& point)
-{
- if (!firstTextBox() || textLength() == 0)
- return createPositionWithAffinity(0, DOWNSTREAM);
-
- LayoutUnit pointLineDirection = firstTextBox()->isHorizontal() ? point.x() : point.y();
- LayoutUnit pointBlockDirection = firstTextBox()->isHorizontal() ? point.y() : point.x();
- bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
-
- InlineTextBox* lastBox = 0;
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild() && !box->nextLeafChild()->isLineBreak())
- box = box->nextTextBox();
-
- RootInlineBox& rootBox = box->root();
- LayoutUnit top = std::min(rootBox.selectionTop(), rootBox.lineTop());
- if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirection == top)) {
- LayoutUnit bottom = rootBox.selectionBottom();
- if (rootBox.nextRootBox())
- bottom = std::min(bottom, rootBox.nextRootBox()->lineTop());
-
- if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockDirection == bottom)) {
- ShouldAffinityBeDownstream shouldAffinityBeDownstream;
- if (lineDirectionPointFitsInBox(pointLineDirection, box, shouldAffinityBeDownstream))
- return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(box, box->offsetForPosition(pointLineDirection.toFloat()), shouldAffinityBeDownstream);
- }
- }
- lastBox = box;
- }
-
- if (lastBox) {
- ShouldAffinityBeDownstream shouldAffinityBeDownstream;
- lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityBeDownstream);
- return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastBox, lastBox->offsetForPosition(pointLineDirection.toFloat()) + lastBox->start(), shouldAffinityBeDownstream);
- }
- return createPositionWithAffinity(0, DOWNSTREAM);
-}
-
-LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
-{
- if (!inlineBox)
- return LayoutRect();
-
- ASSERT(inlineBox->isInlineTextBox());
- if (!inlineBox->isInlineTextBox())
- return LayoutRect();
-
- InlineTextBox* box = toInlineTextBox(inlineBox);
-
- int height = box->root().selectionHeight();
- int top = box->root().selectionTop();
-
- // Go ahead and round left to snap it to the nearest pixel.
- float left = box->positionForOffset(caretOffset);
-
- // Distribute the caret's width to either side of the offset.
- int caretWidthLeftOfOffset = caretWidth / 2;
- left -= caretWidthLeftOfOffset;
- int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset;
-
- left = roundf(left);
-
- float rootLeft = box->root().logicalLeft();
- float rootRight = box->root().logicalRight();
-
- // FIXME: should we use the width of the root inline box or the
- // width of the containing block for this?
- if (extraWidthToEndOfLine)
- *extraWidthToEndOfLine = (box->root().logicalWidth() + rootLeft) - (left + 1);
-
- LayoutBlock* cb = containingBlock();
- const LayoutStyle& cbStyle = cb->styleRef();
-
- float leftEdge;
- float rightEdge;
- leftEdge = std::min<float>(0, rootLeft);
- rightEdge = std::max<float>(cb->logicalWidth().toFloat(), rootRight);
-
- bool rightAligned = false;
- switch (cbStyle.textAlign()) {
- case RIGHT:
- case WEBKIT_RIGHT:
- rightAligned = true;
- break;
- case LEFT:
- case WEBKIT_LEFT:
- case CENTER:
- case WEBKIT_CENTER:
- break;
- case JUSTIFY:
- case TASTART:
- rightAligned = !cbStyle.isLeftToRightDirection();
- break;
- case TAEND:
- rightAligned = cbStyle.isLeftToRightDirection();
- break;
- }
-
- // for dir=auto, use inlineBoxBidiLevel() to test the correct direction for the cursor.
- if (rightAligned && (node() && node()->selfOrAncestorHasDirAutoAttribute())) {
- if (inlineBox->bidiLevel()%2 != 1)
- rightAligned = false;
- }
-
- if (rightAligned) {
- left = std::max(left, leftEdge);
- left = std::min(left, rootRight - caretWidth);
- } else {
- left = std::min(left, rightEdge - caretWidthRightOfOffset);
- left = std::max(left, rootLeft);
- }
-
- return LayoutRect(style()->isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth));
-}
-
-ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
-{
- if (style()->hasTextCombine() && isCombineText()) {
- const RenderCombineText* combineText = toRenderCombineText(this);
- if (combineText->isCombined())
- return combineText->combinedTextWidth(f);
- }
-
- if (f.isFixedPitch() && f.fontDescription().variant() == FontVariantNormal && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
- bool missingGlyph = false;
- float monospaceCharacterWidth = f.spaceWidth();
- float w = 0;
- bool isSpace;
- ASSERT(m_text);
- StringImpl& text = *m_text.impl();
- const LayoutStyle& layoutStyle = styleRef();
- for (int i = start; i < start + len; i++) {
- char c = text[i];
- // If glyph is not present in primary font then we cannot calculate width based on primary
- // font property, we need to call "width" method of Font Object.
- if (!f.primaryFontHasGlyphForCharacter(text[i])) {
- missingGlyph = true;
- break;
- }
- if (c <= space) {
- if (c == space || c == newlineCharacter) {
- w += monospaceCharacterWidth;
- isSpace = true;
- } else if (c == characterTabulation) {
- if (layoutStyle.collapseWhiteSpace()) {
- w += monospaceCharacterWidth;
- isSpace = true;
- } else {
- w += f.tabWidth(layoutStyle.tabSize(), xPos + w);
- isSpace = false;
- }
- } else
- isSpace = false;
- } else {
- w += monospaceCharacterWidth;
- isSpace = false;
- }
- if (isSpace && i > start)
- w += f.fontDescription().wordSpacing();
- }
- if (!missingGlyph)
- return w;
- }
-
- TextRun run = constructTextRun(const_cast<RenderText*>(this), f, this, start, len, styleRef(), textDirection);
- run.setCharactersLength(textLength() - start);
- ASSERT(run.charactersLength() >= run.length());
- run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun::ForceComplex);
- run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
- run.setXPos(xPos);
- return f.width(run, fallbackFonts, glyphOverflow);
-}
-
-void RenderText::trimmedPrefWidths(FloatWillBeLayoutUnit leadWidth,
- FloatWillBeLayoutUnit& firstLineMinWidth, bool& hasBreakableStart,
- FloatWillBeLayoutUnit& lastLineMinWidth, bool& hasBreakableEnd,
- bool& hasBreakableChar, bool& hasBreak,
- FloatWillBeLayoutUnit& firstLineMaxWidth, FloatWillBeLayoutUnit& lastLineMaxWidth,
- FloatWillBeLayoutUnit& minWidth, FloatWillBeLayoutUnit& maxWidth, bool& stripFrontSpaces,
- TextDirection direction)
-{
- bool collapseWhiteSpace = style()->collapseWhiteSpace();
- if (!collapseWhiteSpace)
- stripFrontSpaces = false;
-
- if (m_hasTab || preferredLogicalWidthsDirty())
- computePreferredLogicalWidths(leadWidth);
-
- hasBreakableStart = !stripFrontSpaces && m_hasBreakableStart;
- hasBreakableEnd = m_hasBreakableEnd;
-
- int len = textLength();
-
- if (!len || (stripFrontSpaces && text().impl()->containsOnlyWhitespace())) {
- firstLineMinWidth = FloatWillBeLayoutUnit();
- lastLineMinWidth = FloatWillBeLayoutUnit();
- firstLineMaxWidth = FloatWillBeLayoutUnit();
- lastLineMaxWidth = FloatWillBeLayoutUnit();
- minWidth = FloatWillBeLayoutUnit();
- maxWidth = FloatWillBeLayoutUnit();
- hasBreak = false;
- return;
- }
-
- minWidth = m_minWidth;
- maxWidth = m_maxWidth;
-
- firstLineMinWidth = m_firstLineMinWidth;
- lastLineMinWidth = m_lastLineLineMinWidth;
-
- hasBreakableChar = m_hasBreakableChar;
- hasBreak = m_hasBreak;
-
- ASSERT(m_text);
- StringImpl& text = *m_text.impl();
- if (text[0] == space || (text[0] == newlineCharacter && !style()->preserveNewline()) || text[0] == characterTabulation) {
- const Font& font = style()->font(); // FIXME: This ignores first-line.
- if (stripFrontSpaces) {
- const UChar spaceChar = space;
- TextRun run = constructTextRun(this, font, &spaceChar, 1, styleRef(), direction);
- run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun::ForceComplex);
- float spaceWidth = font.width(run);
- maxWidth -= spaceWidth;
- } else {
- maxWidth += font.fontDescription().wordSpacing();
- }
- }
-
- stripFrontSpaces = collapseWhiteSpace && m_hasEndWhiteSpace;
-
- if (!style()->autoWrap() || minWidth > maxWidth)
- minWidth = maxWidth;
-
- // Compute our max widths by scanning the string for newlines.
- if (hasBreak) {
- const Font& f = style()->font(); // FIXME: This ignores first-line.
- bool firstLine = true;
- firstLineMaxWidth = maxWidth;
- lastLineMaxWidth = maxWidth;
- for (int i = 0; i < len; i++) {
- int linelen = 0;
- while (i + linelen < len && text[i + linelen] != newlineCharacter)
- linelen++;
-
- if (linelen) {
- lastLineMaxWidth = widthFromCache(f, i, linelen, leadWidth + lastLineMaxWidth, direction, 0, 0);
- if (firstLine) {
- firstLine = false;
- leadWidth = FloatWillBeLayoutUnit();
- firstLineMaxWidth = lastLineMaxWidth;
- }
- i += linelen;
- } else if (firstLine) {
- firstLineMaxWidth = FloatWillBeLayoutUnit();
- firstLine = false;
- leadWidth = FloatWillBeLayoutUnit();
- }
-
- if (i == len - 1) {
- // A <pre> run that ends with a newline, as in, e.g.,
- // <pre>Some text\n\n<span>More text</pre>
- lastLineMaxWidth = FloatWillBeLayoutUnit();
- }
- }
- }
-}
-
-float RenderText::minLogicalWidth() const
-{
- if (preferredLogicalWidthsDirty())
- const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
-
- return m_minWidth;
-}
-
-float RenderText::maxLogicalWidth() const
-{
- if (preferredLogicalWidthsDirty())
- const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
-
- return m_maxWidth;
-}
-
-void RenderText::computePreferredLogicalWidths(float leadWidth)
-{
- HashSet<const SimpleFontData*> fallbackFonts;
- GlyphOverflow glyphOverflow;
- computePreferredLogicalWidths(leadWidth, fallbackFonts, glyphOverflow);
-
- // We shouldn't change our mind once we "know".
- ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts || (fallbackFonts.isEmpty() && glyphOverflow.isZero()));
- m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts.isEmpty() && glyphOverflow.isZero();
-}
-
-static inline float hyphenWidth(RenderText* renderer, const Font& font, TextDirection direction)
-{
- const LayoutStyle& style = renderer->styleRef();
- return font.width(constructTextRun(renderer, font, style.hyphenString().string(), style, direction));
-}
-
-void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
-{
- ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts);
-
- m_minWidth = 0;
- m_maxWidth = 0;
- m_firstLineMinWidth = 0;
- m_lastLineLineMinWidth = 0;
-
- if (isBR())
- return;
-
- float currMinWidth = 0;
- float currMaxWidth = 0;
- m_hasBreakableChar = false;
- m_hasBreak = false;
- m_hasTab = false;
- m_hasBreakableStart = false;
- m_hasBreakableEnd = false;
- m_hasEndWhiteSpace = false;
-
- const LayoutStyle& styleToUse = styleRef();
- const Font& f = styleToUse.font(); // FIXME: This ignores first-line.
- float wordSpacing = styleToUse.wordSpacing();
- int len = textLength();
- LazyLineBreakIterator breakIterator(m_text, styleToUse.locale());
- bool needsWordSpacing = false;
- bool ignoringSpaces = false;
- bool isSpace = false;
- bool firstWord = true;
- bool firstLine = true;
- int nextBreakable = -1;
- int lastWordBoundary = 0;
- float cachedWordTrailingSpaceWidth[2] = { 0, 0 }; // LTR, RTL
-
- int firstGlyphLeftOverflow = -1;
-
- bool breakAll = (styleToUse.wordBreak() == BreakAllWordBreak || styleToUse.wordBreak() == BreakWordBreak) && styleToUse.autoWrap();
-
- TextRun textRun(text());
- BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
- BidiCharacterRun* run;
- TextDirection textDirection = styleToUse.direction();
- if (isOverride(styleToUse.unicodeBidi())) {
- run = 0;
- } else {
- BidiStatus status(textDirection, false);
- bidiResolver.setStatus(status);
- bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&textRun, 0));
- bool hardLineBreak = false;
- bool reorderRuns = false;
- bidiResolver.createBidiRunsForLine(TextRunIterator(&textRun, textRun.length()), NoVisualOverride, hardLineBreak, reorderRuns);
- BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
- run = bidiRuns.firstRun();
- }
-
- for (int i = 0; i < len; i++) {
- UChar c = uncheckedCharacterAt(i);
-
- if (run) {
- // Treat adjacent runs with the same resolved directionality
- // (TextDirection as opposed to WTF::Unicode::Direction) as belonging
- // to the same run to avoid breaking unnecessarily.
- while (i >= run->stop() || (run->next() && run->next()->direction() == run->direction()))
- run = run->next();
-
- ASSERT(run);
- ASSERT(i <= run->stop());
- textDirection = run->direction();
- }
-
- bool previousCharacterIsSpace = isSpace;
- bool isNewline = false;
- if (c == newlineCharacter) {
- if (styleToUse.preserveNewline()) {
- m_hasBreak = true;
- isNewline = true;
- isSpace = false;
- } else
- isSpace = true;
- } else if (c == characterTabulation) {
- if (!styleToUse.collapseWhiteSpace()) {
- m_hasTab = true;
- isSpace = false;
- } else
- isSpace = true;
- } else {
- isSpace = c == space;
- }
-
- bool isBreakableLocation = isNewline || (isSpace && styleToUse.autoWrap());
- if (!i)
- m_hasBreakableStart = isBreakableLocation;
- if (i == len - 1) {
- m_hasBreakableEnd = isBreakableLocation;
- m_hasEndWhiteSpace = isNewline || isSpace;
- }
-
- if (!ignoringSpaces && styleToUse.collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
- ignoringSpaces = true;
-
- if (ignoringSpaces && !isSpace)
- ignoringSpaces = false;
-
- // Ignore spaces and soft hyphens
- if (ignoringSpaces) {
- ASSERT(lastWordBoundary == i);
- lastWordBoundary++;
- continue;
- } else if (c == softHyphen) {
- currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
- if (firstGlyphLeftOverflow < 0)
- firstGlyphLeftOverflow = glyphOverflow.left;
- lastWordBoundary = i + 1;
- continue;
- }
-
- bool hasBreak = breakIterator.isBreakable(i, nextBreakable, breakAll ? LineBreakType::BreakAll : LineBreakType::Normal);
- bool betweenWords = true;
- int j = i;
- while (c != newlineCharacter && c != space && c != characterTabulation && (c != softHyphen)) {
- j++;
- if (j == len)
- break;
- c = uncheckedCharacterAt(j);
- if (breakIterator.isBreakable(j, nextBreakable) && characterAt(j - 1) != softHyphen)
- break;
- if (breakAll) {
- betweenWords = false;
- break;
- }
- }
-
- // Terminate word boundary at bidi run boundary.
- if (run)
- j = std::min(j, run->stop() + 1);
- int wordLen = j - i;
- if (wordLen) {
- bool isSpace = (j < len) && c == space;
-
- // Non-zero only when kerning is enabled, in which case we measure words with their trailing
- // space, then subtract its width.
- float wordTrailingSpaceWidth = 0;
- if (isSpace && (f.fontDescription().typesettingFeatures() & Kerning)) {
- ASSERT(textDirection >=0 && textDirection <= 1);
- if (!cachedWordTrailingSpaceWidth[textDirection])
- cachedWordTrailingSpaceWidth[textDirection] = f.width(constructTextRun(this, f, &space, 1, styleToUse, textDirection)) + wordSpacing;
- wordTrailingSpaceWidth = cachedWordTrailingSpaceWidth[textDirection];
- }
-
- float w;
- if (wordTrailingSpaceWidth && isSpace)
- w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth;
- else {
- w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
- if (c == softHyphen)
- currMinWidth += hyphenWidth(this, f, textDirection);
- }
-
- if (firstGlyphLeftOverflow < 0)
- firstGlyphLeftOverflow = glyphOverflow.left;
- currMinWidth += w;
- if (betweenWords) {
- if (lastWordBoundary == i)
- currMaxWidth += w;
- else
- currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
- lastWordBoundary = j;
- }
-
- bool isCollapsibleWhiteSpace = (j < len) && styleToUse.isCollapsibleWhiteSpace(c);
- if (j < len && styleToUse.autoWrap())
- m_hasBreakableChar = true;
-
- // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
- // last word in the run.
- if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
- currMaxWidth += wordSpacing;
-
- if (firstWord) {
- firstWord = false;
- // If the first character in the run is breakable, then we consider ourselves to have a beginning
- // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
- // being appended to a previous text run when considering the total minimum width of the containing block.
- if (hasBreak)
- m_hasBreakableChar = true;
- m_firstLineMinWidth = hasBreak ? 0 : currMinWidth;
- }
- m_lastLineLineMinWidth = currMinWidth;
-
- if (currMinWidth > m_minWidth)
- m_minWidth = currMinWidth;
- currMinWidth = 0;
-
- i += wordLen - 1;
- } else {
- // Nowrap can never be broken, so don't bother setting the
- // breakable character boolean. Pre can only be broken if we encounter a newline.
- if (style()->autoWrap() || isNewline)
- m_hasBreakableChar = true;
-
- if (currMinWidth > m_minWidth)
- m_minWidth = currMinWidth;
- currMinWidth = 0;
-
- if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
- if (firstLine) {
- firstLine = false;
- leadWidth = 0;
- if (!styleToUse.autoWrap())
- m_firstLineMinWidth = currMaxWidth;
- }
-
- if (currMaxWidth > m_maxWidth)
- m_maxWidth = currMaxWidth;
- currMaxWidth = 0;
- } else {
- TextRun run = constructTextRun(this, f, this, i, 1, styleToUse, textDirection);
- run.setCharactersLength(len - i);
- run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun::ForceComplex);
- ASSERT(run.charactersLength() >= run.length());
- run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
- run.setXPos(leadWidth + currMaxWidth);
-
- currMaxWidth += f.width(run);
- glyphOverflow.right = 0;
- needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
- }
- ASSERT(lastWordBoundary == i);
- lastWordBoundary++;
- }
- }
- if (run)
- bidiResolver.runs().deleteRuns();
-
- if (firstGlyphLeftOverflow > 0)
- glyphOverflow.left = firstGlyphLeftOverflow;
-
- if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord))
- currMaxWidth += wordSpacing;
-
- m_minWidth = std::max(currMinWidth, m_minWidth);
- m_maxWidth = std::max(currMaxWidth, m_maxWidth);
-
- if (!styleToUse.autoWrap())
- m_minWidth = m_maxWidth;
-
- if (styleToUse.whiteSpace() == PRE) {
- if (firstLine)
- m_firstLineMinWidth = m_maxWidth;
- m_lastLineLineMinWidth = currMaxWidth;
- }
-
- clearPreferredLogicalWidthsDirty();
-}
-
-bool RenderText::isAllCollapsibleWhitespace() const
-{
- unsigned length = textLength();
- if (is8Bit()) {
- for (unsigned i = 0; i < length; ++i) {
- if (!style()->isCollapsibleWhiteSpace(characters8()[i]))
- return false;
- }
- return true;
- }
- for (unsigned i = 0; i < length; ++i) {
- if (!style()->isCollapsibleWhiteSpace(characters16()[i]))
- return false;
- }
- return true;
-}
-
-bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
-{
- ASSERT(m_text);
- StringImpl& text = *m_text.impl();
- unsigned currPos;
- for (currPos = from;
- currPos < from + len && (text[currPos] == newlineCharacter || text[currPos] == space || text[currPos] == characterTabulation);
- currPos++) { }
- return currPos >= (from + len);
-}
-
-FloatPoint RenderText::firstRunOrigin() const
-{
- return IntPoint(firstRunX(), firstRunY());
-}
-
-float RenderText::firstRunX() const
-{
- return m_firstTextBox ? m_firstTextBox->x().toFloat() : 0;
-}
-
-float RenderText::firstRunY() const
-{
- return m_firstTextBox ? m_firstTextBox->y().toFloat() : 0;
-}
-
-void RenderText::setSelectionState(SelectionState state)
-{
- LayoutObject::setSelectionState(state);
-
- if (canUpdateSelectionOnRootLineBoxes()) {
- if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) {
- int startPos, endPos;
- selectionStartEnd(startPos, endPos);
- if (selectionState() == SelectionStart) {
- endPos = textLength();
-
- // to handle selection from end of text to end of line
- if (startPos && startPos == endPos)
- startPos = endPos - 1;
- } else if (selectionState() == SelectionEnd)
- startPos = 0;
-
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- if (box->isSelected(startPos, endPos)) {
- box->root().setHasSelectedChildren(true);
- }
- }
- } else {
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- box->root().setHasSelectedChildren(state == SelectionInside);
- }
- }
- }
-
- // The containing block can be null in case of an orphaned tree.
- LayoutBlock* containingBlock = this->containingBlock();
- if (containingBlock && !containingBlock->isLayoutView())
- containingBlock->setSelectionState(state);
-}
-
-void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force)
-{
- if (!force && equal(m_text.impl(), text.get()))
- return;
-
- unsigned oldLen = textLength();
- unsigned newLen = text->length();
- int delta = newLen - oldLen;
- unsigned end = len ? offset + len - 1 : offset;
-
- RootInlineBox* firstRootBox = 0;
- RootInlineBox* lastRootBox = 0;
-
- bool dirtiedLines = false;
-
- // Dirty all text boxes that include characters in between offset and offset+len.
- for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
- // FIXME: This shouldn't rely on the end of a dirty line box. See https://bugs.webkit.org/show_bug.cgi?id=97264
- // Text run is entirely before the affected range.
- if (curr->end() < offset)
- continue;
-
- // Text run is entirely after the affected range.
- if (curr->start() > end) {
- curr->offsetRun(delta);
- RootInlineBox* root = &curr->root();
- if (!firstRootBox) {
- firstRootBox = root;
- // The affected area was in between two runs. Go ahead and mark the root box of
- // the run after the affected area as dirty.
- firstRootBox->markDirty();
- dirtiedLines = true;
- }
- lastRootBox = root;
- } else if (curr->end() >= offset && curr->end() <= end) {
- // Text run overlaps with the left end of the affected range.
- curr->dirtyLineBoxes();
- dirtiedLines = true;
- } else if (curr->start() <= offset && curr->end() >= end) {
- // Text run subsumes the affected range.
- curr->dirtyLineBoxes();
- dirtiedLines = true;
- } else if (curr->start() <= end && curr->end() >= end) {
- // Text run overlaps with right end of the affected range.
- curr->dirtyLineBoxes();
- dirtiedLines = true;
- }
- }
-
- // Now we have to walk all of the clean lines and adjust their cached line break information
- // to reflect our updated offsets.
- if (lastRootBox)
- lastRootBox = lastRootBox->nextRootBox();
- if (firstRootBox) {
- RootInlineBox* prev = firstRootBox->prevRootBox();
- if (prev)
- firstRootBox = prev;
- } else if (lastTextBox()) {
- ASSERT(!lastRootBox);
- firstRootBox = &lastTextBox()->root();
- firstRootBox->markDirty();
- dirtiedLines = true;
- }
- for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
- if (curr->lineBreakObj() == this && curr->lineBreakPos() > end)
- curr->setLineBreakPos(clampTo<int>(curr->lineBreakPos() + delta));
- }
-
- // If the text node is empty, dirty the line where new text will be inserted.
- if (!firstTextBox() && parent()) {
- parent()->dirtyLinesFromChangedChild(this);
- dirtiedLines = true;
- }
-
- m_linesDirty = dirtiedLines;
- setText(text, force || dirtiedLines);
-}
-
-void RenderText::transformText()
-{
- if (RefPtr<StringImpl> textToTransform = originalText())
- setText(textToTransform.release(), true);
-}
-
-static inline bool isInlineFlowOrEmptyText(const LayoutObject* o)
-{
- if (o->isLayoutInline())
- return true;
- if (!o->isText())
- return false;
- return toRenderText(o)->text().isEmpty();
-}
-
-UChar RenderText::previousCharacter() const
-{
- // find previous text renderer if one exists
- const LayoutObject* previousText = previousInPreOrder();
- for (; previousText; previousText = previousText->previousInPreOrder())
- if (!isInlineFlowOrEmptyText(previousText))
- break;
- UChar prev = space;
- if (previousText && previousText->isText())
- if (StringImpl* previousString = toRenderText(previousText)->text().impl())
- prev = (*previousString)[previousString->length() - 1];
- return prev;
-}
-
-void RenderText::addLayerHitTestRects(LayerHitTestRects&, const Layer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
-{
- // Text nodes aren't event targets, so don't descend any further.
-}
-
-void applyTextTransform(const LayoutStyle* style, String& text, UChar previousCharacter)
-{
- if (!style)
- return;
-
- switch (style->textTransform()) {
- case TTNONE:
- break;
- case CAPITALIZE:
- makeCapitalized(&text, previousCharacter);
- break;
- case UPPERCASE:
- text = text.upper(style->locale());
- break;
- case LOWERCASE:
- text = text.lower(style->locale());
- break;
- }
-}
-
-void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
-{
- ASSERT(text);
- m_text = text;
-
- if (style()) {
- applyTextTransform(style(), m_text, previousCharacter());
-
- // We use the same characters here as for list markers.
- // See the listMarkerText function in LayoutListMarker.cpp.
- switch (style()->textSecurity()) {
- case TSNONE:
- break;
- case TSCIRCLE:
- secureText(whiteBullet);
- break;
- case TSDISC:
- secureText(bullet);
- break;
- case TSSQUARE:
- secureText(blackSquare);
- }
- }
-
- ASSERT(m_text);
- ASSERT(!isBR() || (textLength() == 1 && m_text[0] == newlineCharacter));
-
- m_isAllASCII = m_text.containsOnlyASCII();
- m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
-}
-
-void RenderText::secureText(UChar mask)
-{
- if (!m_text.length())
- return;
-
- int lastTypedCharacterOffsetToReveal = -1;
- UChar revealedText;
- SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->get(this) : 0;
- if (secureTextTimer && secureTextTimer->isActive()) {
- lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOffset();
- if (lastTypedCharacterOffsetToReveal >= 0)
- revealedText = m_text[lastTypedCharacterOffsetToReveal];
- }
-
- m_text.fill(mask);
- if (lastTypedCharacterOffsetToReveal >= 0) {
- m_text.replace(lastTypedCharacterOffsetToReveal, 1, String(&revealedText, 1));
- // m_text may be updated later before timer fires. We invalidate the lastTypedCharacterOffset to avoid inconsistency.
- secureTextTimer->invalidate();
- }
-}
-
-void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
-{
- ASSERT(text);
-
- if (!force && equal(m_text.impl(), text.get()))
- return;
-
- setTextInternal(text);
- // If preferredLogicalWidthsDirty() of an orphan child is true, LayoutObjectChildList::
- // insertChildNode() fails to set true to owner. To avoid that, we call
- // setNeedsLayoutAndPrefWidthsRecalc() only if this RenderText has parent.
- if (parent())
- setNeedsLayoutAndPrefWidthsRecalc();
- m_knownToHaveNoOverflowAndNoFallbackFonts = false;
-
- if (AXObjectCache* cache = document().existingAXObjectCache())
- cache->textChanged(this);
-}
-
-void RenderText::dirtyOrDeleteLineBoxesIfNeeded(bool fullLayout)
-{
- if (fullLayout)
- deleteTextBoxes();
- else if (!m_linesDirty)
- dirtyLineBoxes();
- m_linesDirty = false;
-}
-
-void RenderText::dirtyLineBoxes()
-{
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- box->dirtyLineBoxes();
- m_linesDirty = false;
-}
-
-InlineTextBox* RenderText::createTextBox(int start, unsigned short length)
-{
- return new InlineTextBox(*this, start, length);
-}
-
-InlineTextBox* RenderText::createInlineTextBox(int start, unsigned short length)
-{
- InlineTextBox* textBox = createTextBox(start, length);
- if (!m_firstTextBox)
- m_firstTextBox = m_lastTextBox = textBox;
- else {
- m_lastTextBox->setNextTextBox(textBox);
- textBox->setPreviousTextBox(m_lastTextBox);
- m_lastTextBox = textBox;
- }
- return textBox;
-}
-
-void RenderText::positionLineBox(InlineBox* box)
-{
- InlineTextBox* s = toInlineTextBox(box);
-
- // FIXME: should not be needed!!!
- if (!s->len()) {
- // We want the box to be destroyed.
- s->remove(DontMarkLineBoxes);
- if (m_firstTextBox == s)
- m_firstTextBox = s->nextTextBox();
- else
- s->prevTextBox()->setNextTextBox(s->nextTextBox());
- if (m_lastTextBox == s)
- m_lastTextBox = s->prevTextBox();
- else
- s->nextTextBox()->setPreviousTextBox(s->prevTextBox());
- s->destroy();
- return;
- }
-
- m_containsReversedText |= !s->isLeftToRightDirection();
-}
-
-float RenderText::width(unsigned from, unsigned len, float xPos, TextDirection textDirection, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
-{
- if (from >= textLength())
- return 0;
-
- if (from + len > textLength())
- len = textLength() - from;
-
- return width(from, len, style(firstLine)->font(), xPos, textDirection, fallbackFonts, glyphOverflow);
-}
-
-float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
-{
- ASSERT(from + len <= textLength());
- if (!textLength())
- return 0;
-
- float w;
- if (&f == &style()->font()) {
- if (!style()->preserveNewline() && !from && len == textLength() && (!glyphOverflow || !glyphOverflow->computeBounds)) {
- if (fallbackFonts) {
- ASSERT(glyphOverflow);
- if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
- const_cast<RenderText*>(this)->computePreferredLogicalWidths(0, *fallbackFonts, *glyphOverflow);
- // We shouldn't change our mind once we "know".
- ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts
- || (fallbackFonts->isEmpty() && glyphOverflow->isZero()));
- m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts->isEmpty() && glyphOverflow->isZero();
- }
- w = m_maxWidth;
- } else {
- w = maxLogicalWidth();
- }
- } else {
- w = widthFromCache(f, from, len, xPos, textDirection, fallbackFonts, glyphOverflow);
- }
- } else {
- TextRun run = constructTextRun(const_cast<RenderText*>(this), f, this, from, len, styleRef(), textDirection);
- run.setCharactersLength(textLength() - from);
- ASSERT(run.charactersLength() >= run.length());
-
- run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun::ForceComplex);
- run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
- run.setXPos(xPos);
- w = f.width(run, fallbackFonts, glyphOverflow);
- }
-
- return w;
-}
-
-IntRect RenderText::linesBoundingBox() const
-{
- IntRect result;
-
- ASSERT(!firstTextBox() == !lastTextBox()); // Either both are null or both exist.
- if (firstTextBox() && lastTextBox()) {
- // Return the width of the minimal left side and the maximal right side.
- float logicalLeftSide = 0;
- float logicalRightSide = 0;
- for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
- if (curr == firstTextBox() || curr->logicalLeft() < logicalLeftSide)
- logicalLeftSide = curr->logicalLeft();
- if (curr == firstTextBox() || curr->logicalRight() > logicalRightSide)
- logicalRightSide = curr->logicalRight();
- }
-
- bool isHorizontal = style()->isHorizontalWritingMode();
-
- float x = isHorizontal ? logicalLeftSide : firstTextBox()->x().toFloat();
- float y = isHorizontal ? firstTextBox()->y().toFloat() : logicalLeftSide;
- float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTextBox()->logicalBottom() - x;
- float height = isHorizontal ? lastTextBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
- result = enclosingIntRect(FloatRect(x, y, width, height));
- }
-
- return result;
-}
-
-LayoutRect RenderText::linesVisualOverflowBoundingBox() const
-{
- if (!firstTextBox())
- return LayoutRect();
-
- // Return the width of the minimal left side and the maximal right side.
- LayoutUnit logicalLeftSide = LayoutUnit::max();
- LayoutUnit logicalRightSide = LayoutUnit::min();
- for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
- LayoutRect logicalVisualOverflow = curr->logicalOverflowRect();
- logicalLeftSide = std::min(logicalLeftSide, logicalVisualOverflow.x());
- logicalRightSide = std::max(logicalRightSide, logicalVisualOverflow.maxX());
- }
-
- LayoutUnit logicalTop = firstTextBox()->logicalTopVisualOverflow();
- LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
- LayoutUnit logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - logicalTop;
-
- LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
- if (!style()->isHorizontalWritingMode())
- rect = rect.transposedRect();
- return rect;
-}
-
-LayoutRect RenderText::clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
-{
- if (style()->visibility() != VISIBLE)
- return LayoutRect();
-
- LayoutRect paintInvalidationRect(linesVisualOverflowBoundingBox());
- mapRectToPaintInvalidationBacking(paintInvalidationContainer, paintInvalidationRect, paintInvalidationState);
- return paintInvalidationRect;
-}
-
-LayoutRect RenderText::selectionRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer) const
-{
- ASSERT(!needsLayout());
-
- if (selectionState() == SelectionNone)
- return LayoutRect();
- LayoutBlock* cb = containingBlock();
- if (!cb)
- return LayoutRect();
-
- // Now calculate startPos and endPos for painting selection.
- // We include a selection while endPos > 0
- int startPos, endPos;
- if (selectionState() == SelectionInside) {
- // We are fully selected.
- startPos = 0;
- endPos = textLength();
- } else {
- selectionStartEnd(startPos, endPos);
- if (selectionState() == SelectionStart)
- endPos = textLength();
- else if (selectionState() == SelectionEnd)
- startPos = 0;
- }
-
- LayoutRect rect;
-
- if (startPos == endPos)
- return rect;
-
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- rect.unite(box->localSelectionRect(startPos, endPos));
- rect.unite(LayoutRect(ellipsisRectForBox(box, startPos, endPos)));
- }
-
- mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, 0);
- // FIXME: groupedMapping() leaks the squashing abstraction.
- if (paintInvalidationContainer->layer()->groupedMapping())
- Layer::mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect);
- return rect;
-}
-
-int RenderText::caretMinOffset() const
-{
- InlineTextBox* box = firstTextBox();
- if (!box)
- return 0;
- int minOffset = box->start();
- for (box = box->nextTextBox(); box; box = box->nextTextBox())
- minOffset = std::min<int>(minOffset, box->start());
- return minOffset;
-}
-
-int RenderText::caretMaxOffset() const
-{
- InlineTextBox* box = lastTextBox();
- if (!lastTextBox())
- return textLength();
-
- int maxOffset = box->start() + box->len();
- for (box = box->prevTextBox(); box; box = box->prevTextBox())
- maxOffset = std::max<int>(maxOffset, box->start() + box->len());
- return maxOffset;
-}
-
-unsigned RenderText::renderedTextLength() const
-{
- int l = 0;
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- l += box->len();
- return l;
-}
-
-int RenderText::previousOffset(int current) const
-{
- if (isAllASCII() || m_text.is8Bit())
- return current - 1;
-
- StringImpl* textImpl = m_text.impl();
- TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
- if (!iterator)
- return current - 1;
-
- long result = iterator->preceding(current);
- if (result == TextBreakDone)
- result = current - 1;
-
-
- return result;
-}
-
-#if OS(POSIX)
-
-#define HANGUL_CHOSEONG_START (0x1100)
-#define HANGUL_CHOSEONG_END (0x115F)
-#define HANGUL_JUNGSEONG_START (0x1160)
-#define HANGUL_JUNGSEONG_END (0x11A2)
-#define HANGUL_JONGSEONG_START (0x11A8)
-#define HANGUL_JONGSEONG_END (0x11F9)
-#define HANGUL_SYLLABLE_START (0xAC00)
-#define HANGUL_SYLLABLE_END (0xD7AF)
-#define HANGUL_JONGSEONG_COUNT (28)
-
-enum HangulState {
- HangulStateL,
- HangulStateV,
- HangulStateT,
- HangulStateLV,
- HangulStateLVT,
- HangulStateBreak
-};
-
-inline bool isHangulLVT(UChar32 character)
-{
- return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
-}
-
-inline bool isMark(UChar32 c)
-{
- int8_t charType = u_charType(c);
- return charType == U_NON_SPACING_MARK || charType == U_ENCLOSING_MARK || charType == U_COMBINING_SPACING_MARK;
-}
-
-inline bool isRegionalIndicator(UChar32 c)
-{
- // National flag emoji each consists of a pair of regional indicator symbols.
- return 0x1F1E6 <= c && c <= 0x1F1FF;
-}
-
-#endif
-
-int RenderText::previousOffsetForBackwardDeletion(int current) const
-{
-#if OS(POSIX)
- ASSERT(m_text);
- StringImpl& text = *m_text.impl();
- UChar32 character;
- bool sawRegionalIndicator = false;
- while (current > 0) {
- if (U16_IS_TRAIL(text[--current]))
- --current;
- if (current < 0)
- break;
-
- UChar32 character = text.characterStartingAt(current);
-
- if (sawRegionalIndicator) {
- // We don't check if the pair of regional indicator symbols before current position can actually be combined
- // into a flag, and just delete it. This may not agree with how the pair is rendered in edge cases,
- // but is good enough in practice.
- if (isRegionalIndicator(character))
- break;
- // Don't delete a preceding character that isn't a regional indicator symbol.
- U16_FWD_1_UNSAFE(text, current);
- }
-
- // We don't combine characters in Armenian ... Limbu range for backward deletion.
- if ((character >= 0x0530) && (character < 0x1950))
- break;
-
- if (isRegionalIndicator(character)) {
- sawRegionalIndicator = true;
- continue;
- }
-
- if (!isMark(character) && (character != 0xFF9E) && (character != 0xFF9F))
- break;
- }
-
- if (current <= 0)
- return current;
-
- // Hangul
- character = text.characterStartingAt(current);
- if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) {
- HangulState state;
-
- if (character < HANGUL_JUNGSEONG_START)
- state = HangulStateL;
- else if (character < HANGUL_JONGSEONG_START)
- state = HangulStateV;
- else if (character < HANGUL_SYLLABLE_START)
- state = HangulStateT;
- else
- state = isHangulLVT(character) ? HangulStateLVT : HangulStateLV;
-
- while (current > 0 && ((character = text.characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) {
- switch (state) {
- case HangulStateV:
- if (character <= HANGUL_CHOSEONG_END)
- state = HangulStateL;
- else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END) && !isHangulLVT(character))
- state = HangulStateLV;
- else if (character > HANGUL_JUNGSEONG_END)
- state = HangulStateBreak;
- break;
- case HangulStateT:
- if ((character >= HANGUL_JUNGSEONG_START) && (character <= HANGUL_JUNGSEONG_END))
- state = HangulStateV;
- else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))
- state = (isHangulLVT(character) ? HangulStateLVT : HangulStateLV);
- else if (character < HANGUL_JUNGSEONG_START)
- state = HangulStateBreak;
- break;
- default:
- state = (character < HANGUL_JUNGSEONG_START) ? HangulStateL : HangulStateBreak;
- break;
- }
- if (state == HangulStateBreak)
- break;
-
- --current;
- }
- }
-
- return current;
-#else
- // Platforms other than Unix-like delete by one code point.
- if (U16_IS_TRAIL(m_text[--current]))
- --current;
- if (current < 0)
- current = 0;
- return current;
-#endif
-}
-
-int RenderText::nextOffset(int current) const
-{
- if (isAllASCII() || m_text.is8Bit())
- return current + 1;
-
- StringImpl* textImpl = m_text.impl();
- TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(), textImpl->length());
- if (!iterator)
- return current + 1;
-
- long result = iterator->following(current);
- if (result == TextBreakDone)
- result = current + 1;
-
- return result;
-}
-
-bool RenderText::computeCanUseSimpleFontCodePath() const
-{
- if (isAllASCII() || m_text.is8Bit())
- return true;
- return Character::characterRangeCodePath(characters16(), length()) == SimplePath;
-}
-
-#if ENABLE(ASSERT)
-
-void RenderText::checkConsistency() const
-{
-#ifdef CHECK_CONSISTENCY
- const InlineTextBox* prev = 0;
- for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) {
- ASSERT(child->renderer() == this);
- ASSERT(child->prevTextBox() == prev);
- prev = child;
- }
- ASSERT(prev == m_lastTextBox);
-#endif
-}
-
-#endif
-
-void RenderText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset)
-{
- if (!gSecureTextTimers)
- gSecureTextTimers = new SecureTextTimerMap;
-
- SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this);
- if (!secureTextTimer) {
- secureTextTimer = new SecureTextTimer(this);
- gSecureTextTimers->add(this, secureTextTimer);
- }
- secureTextTimer->restartWithNewText(lastTypedCharacterOffset);
-}
-
-PassRefPtr<AbstractInlineTextBox> RenderText::firstAbstractInlineTextBox()
-{
- return AbstractInlineTextBox::getOrCreate(this, m_firstTextBox);
-}
-
-void RenderText::invalidateDisplayItemClients(DisplayItemList* displayItemList) const
-{
- LayoutObject::invalidateDisplayItemClients(displayItemList);
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- displayItemList->invalidate(box->displayItemClient());
-}
-
-} // namespace blink
« no previous file with comments | « Source/core/rendering/RenderText.h ('k') | Source/core/rendering/RenderTextFragment.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698