summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering/RenderText.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/rendering/RenderText.cpp')
-rw-r--r--WebCore/rendering/RenderText.cpp262
1 files changed, 176 insertions, 86 deletions
diff --git a/WebCore/rendering/RenderText.cpp b/WebCore/rendering/RenderText.cpp
index 4653273..90ad6d8 100644
--- a/WebCore/rendering/RenderText.cpp
+++ b/WebCore/rendering/RenderText.cpp
@@ -36,8 +36,10 @@
#include "RenderBlock.h"
#include "RenderLayer.h"
#include "RenderView.h"
+#include "StringBuffer.h"
#include "Text.h"
#include "TextBreakIterator.h"
+#include "TextResourceDecoder.h"
#include "VisiblePosition.h"
#include "break_lines.h"
#include <wtf/AlwaysInline.h>
@@ -48,16 +50,46 @@ using namespace Unicode;
namespace WebCore {
-// FIXME: Move to StringImpl.h eventually.
-static inline bool charactersAreAllASCII(StringImpl* text)
+static void makeCapitalized(String* string, UChar previous)
{
- return charactersAreAllASCII(text->characters(), text->length());
+ if (string->isNull())
+ return;
+
+ unsigned length = string->length();
+ const UChar* characters = string->characters();
+
+ StringBuffer stringWithPrevious(length + 1);
+ stringWithPrevious[0] = previous == noBreakSpace ? ' ' : 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 (characters[i - 1] == noBreakSpace)
+ stringWithPrevious[i] = ' ';
+ else
+ stringWithPrevious[i] = characters[i - 1];
+ }
+
+ TextBreakIterator* boundary = wordBreakIterator(stringWithPrevious.characters(), length + 1);
+ if (!boundary)
+ return;
+
+ StringBuffer data(length);
+
+ int32_t endOfWord;
+ int32_t startOfWord = textBreakFirst(boundary);
+ for (endOfWord = textBreakNext(boundary); endOfWord != TextBreakDone; startOfWord = endOfWord, endOfWord = textBreakNext(boundary)) {
+ if (startOfWord != 0) // Ignore first char of previous string
+ data[startOfWord - 1] = characters[startOfWord - 1] == noBreakSpace ? noBreakSpace : toTitleCase(stringWithPrevious[startOfWord]);
+ for (int i = startOfWord + 1; i < endOfWord; i++)
+ data[i - 1] = characters[i - 1];
+ }
+
+ *string = String::adopt(data);
}
RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
: RenderObject(node)
, m_minWidth(-1)
- , m_text(document()->displayStringModifiedByEncoding(str))
+ , m_text(str)
, m_firstTextBox(0)
, m_lastTextBox(0)
, m_maxWidth(-1)
@@ -66,8 +98,9 @@ RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
, m_hasTab(false)
, m_linesDirty(false)
, m_containsReversedText(false)
- , m_isAllASCII(charactersAreAllASCII(m_text.get()))
- , m_knownNotToUseFallbackFonts(false)
+ , m_isAllASCII(m_text.containsOnlyASCII())
+ , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
+ , m_needsTranscoding(false)
{
ASSERT(m_text);
@@ -104,6 +137,11 @@ bool RenderText::isWordBreak() const
return false;
}
+void RenderText::updateNeedsTranscoding()
+{
+ m_needsTranscoding = document()->decoder() && document()->decoder()->encoding().backslashAsCurrencySymbol() != '\\';
+}
+
void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
// There is no need to ever schedule repaints from a style change of a text run, since
@@ -112,13 +150,18 @@ void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl
// need to relayout.
if (diff == StyleDifferenceLayout) {
setNeedsLayoutAndPrefWidthsRecalc();
- m_knownNotToUseFallbackFonts = false;
+ m_knownToHaveNoOverflowAndNoFallbackFonts = false;
+ }
+
+ bool needsResetText = false;
+ if (!oldStyle) {
+ updateNeedsTranscoding();
+ needsResetText = m_needsTranscoding;
}
ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
-
- if (oldTransform != style()->textTransform() || oldSecurity != style()->textSecurity()) {
+ if (needsResetText || oldTransform != style()->textTransform() || oldSecurity != style()->textSecurity()) {
if (RefPtr<StringImpl> textToTransform = originalText())
setText(textToTransform.release(), true);
}
@@ -150,9 +193,9 @@ void RenderText::extractTextBox(InlineTextBox* box)
if (box == m_firstTextBox)
m_firstTextBox = 0;
if (box->prevTextBox())
- box->prevTextBox()->setNextLineBox(0);
- box->setPreviousLineBox(0);
- for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox())
+ box->prevTextBox()->setNextTextBox(0);
+ box->setPreviousTextBox(0);
+ for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox())
curr->setExtracted();
checkConsistency();
@@ -163,8 +206,8 @@ void RenderText::attachTextBox(InlineTextBox* box)
checkConsistency();
if (m_lastTextBox) {
- m_lastTextBox->setNextLineBox(box);
- box->setPreviousLineBox(m_lastTextBox);
+ m_lastTextBox->setNextTextBox(box);
+ box->setPreviousTextBox(m_lastTextBox);
} else
m_firstTextBox = box;
InlineTextBox* last = box;
@@ -186,9 +229,9 @@ void RenderText::removeTextBox(InlineTextBox* box)
if (box == m_lastTextBox)
m_lastTextBox = box->prevTextBox();
if (box->nextTextBox())
- box->nextTextBox()->setPreviousLineBox(box->prevTextBox());
+ box->nextTextBox()->setPreviousTextBox(box->prevTextBox());
if (box->prevTextBox())
- box->prevTextBox()->setNextLineBox(box->nextTextBox());
+ box->prevTextBox()->setNextTextBox(box->nextTextBox());
checkConsistency();
}
@@ -434,7 +477,7 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e
return IntRect(left, top, caretWidth, height);
}
-ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int xPos, HashSet<const SimpleFontData*>* fallbackFonts) const
+ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
{
if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII) {
int monospaceCharacterWidth = f.spaceWidth();
@@ -442,8 +485,10 @@ ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len,
int w = 0;
bool isSpace;
bool previousCharWasSpace = true; // FIXME: Preserves historical behavior, but seems wrong for start > 0.
+ ASSERT(m_text);
+ StringImpl& text = *m_text.impl();
for (int i = start; i < start + len; i++) {
- char c = (*m_text)[i];
+ char c = text[i];
if (c <= ' ') {
if (c == ' ' || c == '\n') {
w += monospaceCharacterWidth;
@@ -464,7 +509,7 @@ ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len,
return w;
}
- return f.width(TextRun(text()->characters() + start, len, allowTabs(), xPos), fallbackFonts);
+ return f.width(TextRun(text()->characters() + start, len, allowTabs(), xPos), fallbackFonts, glyphOverflow);
}
void RenderText::trimmedPrefWidths(int leadWidth,
@@ -486,7 +531,7 @@ void RenderText::trimmedPrefWidths(int leadWidth,
int len = textLength();
- if (!len || (stripFrontSpaces && m_text->containsOnlyWhitespace())) {
+ if (!len || (stripFrontSpaces && text()->containsOnlyWhitespace())) {
beginMinW = 0;
endMinW = 0;
beginMaxW = 0;
@@ -506,7 +551,9 @@ void RenderText::trimmedPrefWidths(int leadWidth,
hasBreakableChar = m_hasBreakableChar;
hasBreak = m_hasBreak;
- if ((*m_text)[0] == ' ' || ((*m_text)[0] == '\n' && !style()->preserveNewline()) || (*m_text)[0] == '\t') {
+ ASSERT(m_text);
+ StringImpl& text = *m_text.impl();
+ if (text[0] == ' ' || (text[0] == '\n' && !style()->preserveNewline()) || text[0] == '\t') {
const Font& f = style()->font(); // FIXME: This ignores first-line.
if (stripFrontSpaces) {
const UChar space = ' ';
@@ -529,11 +576,11 @@ void RenderText::trimmedPrefWidths(int leadWidth,
endMaxW = maxW;
for (int i = 0; i < len; i++) {
int linelen = 0;
- while (i + linelen < len && (*m_text)[i + linelen] != '\n')
+ while (i + linelen < len && text[i + linelen] != '\n')
linelen++;
if (linelen) {
- endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW, 0);
+ endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW, 0, 0);
if (firstLine) {
firstLine = false;
leadWidth = 0;
@@ -578,14 +625,15 @@ int RenderText::maxPrefWidth() const
void RenderText::calcPrefWidths(int leadWidth)
{
HashSet<const SimpleFontData*> fallbackFonts;
- calcPrefWidths(leadWidth, fallbackFonts);
- if (fallbackFonts.isEmpty())
- m_knownNotToUseFallbackFonts = true;
+ GlyphOverflow glyphOverflow;
+ calcPrefWidths(leadWidth, fallbackFonts, glyphOverflow);
+ if (fallbackFonts.isEmpty() && !glyphOverflow.left && !glyphOverflow.right && !glyphOverflow.top && !glyphOverflow.bottom)
+ m_knownToHaveNoOverflowAndNoFallbackFonts = true;
}
-void RenderText::calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& fallbackFonts)
+void RenderText::calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
{
- ASSERT(m_hasTab || prefWidthsDirty() || !m_knownNotToUseFallbackFonts);
+ ASSERT(m_hasTab || prefWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts);
m_minWidth = 0;
m_beginMinWidth = 0;
@@ -615,6 +663,8 @@ void RenderText::calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& f
int nextBreakable = -1;
int lastWordBoundary = 0;
+ int firstGlyphLeftOverflow = -1;
+
bool breakNBSP = style()->autoWrap() && style()->nbspMode() == SPACE;
bool breakAll = (style()->wordBreak() == BreakAllWordBreak || style()->wordBreak() == BreakWordBreak) && style()->autoWrap();
@@ -657,7 +707,9 @@ void RenderText::calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& f
lastWordBoundary++;
continue;
} else if (c == softHyphen) {
- currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts);
+ currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
+ if (firstGlyphLeftOverflow < 0)
+ firstGlyphLeftOverflow = glyphOverflow.left;
lastWordBoundary = i + 1;
continue;
}
@@ -680,13 +732,15 @@ void RenderText::calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& f
int wordLen = j - i;
if (wordLen) {
- int w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts);
+ int w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
+ if (firstGlyphLeftOverflow < 0)
+ firstGlyphLeftOverflow = glyphOverflow.left;
currMinWidth += w;
if (betweenWords) {
if (lastWordBoundary == i)
currMaxWidth += w;
else
- currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts);
+ currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
lastWordBoundary = j;
}
@@ -739,6 +793,7 @@ void RenderText::calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& f
currMaxWidth = 0;
} else {
currMaxWidth += f.width(TextRun(txt + i, 1, allowTabs(), leadWidth + currMaxWidth));
+ glyphOverflow.right = 0;
needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
}
ASSERT(lastWordBoundary == i);
@@ -746,6 +801,9 @@ void RenderText::calcPrefWidths(int leadWidth, HashSet<const SimpleFontData*>& f
}
}
+ if (firstGlyphLeftOverflow > 0)
+ glyphOverflow.left = firstGlyphLeftOverflow;
+
if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord))
currMaxWidth += wordSpacing;
@@ -777,9 +835,11 @@ bool RenderText::isAllCollapsibleWhitespace()
bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
{
+ ASSERT(m_text);
+ StringImpl& text = *m_text.impl();
unsigned currPos;
for (currPos = from;
- currPos < from + len && ((*m_text)[currPos] == '\n' || (*m_text)[currPos] == ' ' || (*m_text)[currPos] == '\t');
+ currPos < from + len && (text[currPos] == '\n' || text[currPos] == ' ' || text[currPos] == '\t');
currPos++) { }
return currPos >= (from + len);
}
@@ -912,7 +972,7 @@ void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset,
setText(text, force);
}
-static inline bool isInlineFlowOrEmptyText(RenderObject* o)
+static inline bool isInlineFlowOrEmptyText(const RenderObject* o)
{
if (o->isRenderInline())
return true;
@@ -924,10 +984,10 @@ static inline bool isInlineFlowOrEmptyText(RenderObject* o)
return !text->length();
}
-UChar RenderText::previousCharacter()
+UChar RenderText::previousCharacter() const
{
// find previous text renderer if one exists
- RenderObject* previousText = this;
+ const RenderObject* previousText = this;
while ((previousText = previousText->previousInPreOrder()))
if (!isInlineFlowOrEmptyText(previousText))
break;
@@ -938,10 +998,31 @@ UChar RenderText::previousCharacter()
return prev;
}
+void RenderText::transformText(String& text) const
+{
+ ASSERT(style());
+ switch (style()->textTransform()) {
+ case TTNONE:
+ break;
+ case CAPITALIZE:
+ makeCapitalized(&text, previousCharacter());
+ break;
+ case UPPERCASE:
+ text.makeUpper();
+ break;
+ case LOWERCASE:
+ text.makeLower();
+ break;
+ }
+}
+
void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
{
ASSERT(text);
- m_text = document()->displayStringModifiedByEncoding(text);
+ if (m_needsTranscoding)
+ m_text = document()->displayStringModifiedByEncoding(text);
+ else
+ m_text = text;
ASSERT(m_text);
#if ENABLE(SVG)
@@ -952,7 +1033,7 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
// characters into space characters. Then, it will draw all space characters, including
// leading, trailing and multiple contiguous space characters.
- m_text = m_text->replace('\n', ' ');
+ m_text.replace('\n', ' ');
// If xml:space="preserve" is set, white-space is set to "pre", which
// preserves leading, trailing & contiguous space character for us.
@@ -963,70 +1044,71 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
// Then, it will strip off all leading and trailing space characters.
// Then, all contiguous space characters will be consolidated.
- m_text = m_text->replace('\n', StringImpl::empty());
+ m_text.replace('\n', StringImpl::empty());
// If xml:space="default" is set, white-space is set to "nowrap", which handles
// leading, trailing & contiguous space character removal for us.
}
- m_text = m_text->replace('\t', ' ');
+ m_text.replace('\t', ' ');
}
#endif
if (style()) {
- switch (style()->textTransform()) {
- case TTNONE:
- break;
- case CAPITALIZE: {
- m_text = m_text->capitalize(previousCharacter());
- break;
- }
- case UPPERCASE:
- m_text = m_text->upper();
- break;
- case LOWERCASE:
- m_text = m_text->lower();
- break;
- }
+ transformText(m_text);
// We use the same characters here as for list markers.
// See the listMarkerText function in RenderListMarker.cpp.
switch (style()->textSecurity()) {
- case TSNONE:
- break;
- case TSCIRCLE:
- m_text = m_text->secure(whiteBullet);
- break;
- case TSDISC:
- m_text = m_text->secure(bullet);
- break;
- case TSSQUARE:
- m_text = m_text->secure(blackSquare);
+ case TSNONE:
+ break;
+ case TSCIRCLE:
+ m_text.makeSecure(whiteBullet);
+ break;
+ case TSDISC:
+ m_text.makeSecure(bullet);
+ break;
+ case TSSQUARE:
+ m_text.makeSecure(blackSquare);
}
}
ASSERT(m_text);
- ASSERT(!isBR() || (textLength() == 1 && (*m_text)[0] == '\n'));
+ ASSERT(!isBR() || (textLength() == 1 && m_text[0] == '\n'));
- m_isAllASCII = charactersAreAllASCII(m_text.get());
+ m_isAllASCII = m_text.containsOnlyASCII();
}
void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
{
ASSERT(text);
- if (!force && equal(m_text.get(), text.get()))
+ if (!force && equal(m_text.impl(), text.get()))
return;
setTextInternal(text);
setNeedsLayoutAndPrefWidthsRecalc();
- m_knownNotToUseFallbackFonts = false;
+ m_knownToHaveNoOverflowAndNoFallbackFonts = false;
AXObjectCache* axObjectCache = document()->axObjectCache();
if (axObjectCache->accessibilityEnabled())
axObjectCache->contentChanged(this);
}
+String RenderText::textWithoutTranscoding() const
+{
+ // If m_text isn't transcoded or is secure, we can just return the modified text.
+ if (!m_needsTranscoding || style()->textSecurity() != TSNONE)
+ return text();
+
+ // Otherwise, we should use original text. If text-transform is
+ // specified, we should transform the text on the fly.
+ String text = originalText();
+ if (style())
+ transformText(text);
+ return text;
+}
+
int RenderText::lineHeight(bool firstLine, bool) const
{
// Always use the interior line height of the parent (e.g., if our parent is an inline block).
@@ -1055,8 +1137,8 @@ InlineTextBox* RenderText::createInlineTextBox()
if (!m_firstTextBox)
m_firstTextBox = m_lastTextBox = textBox;
else {
- m_lastTextBox->setNextLineBox(textBox);
- textBox->setPreviousLineBox(m_lastTextBox);
+ m_lastTextBox->setNextTextBox(textBox);
+ textBox->setPreviousTextBox(m_lastTextBox);
m_lastTextBox = textBox;
}
textBox->setIsText(true);
@@ -1074,11 +1156,11 @@ void RenderText::positionLineBox(InlineBox* box)
if (m_firstTextBox == s)
m_firstTextBox = s->nextTextBox();
else
- s->prevTextBox()->setNextLineBox(s->nextTextBox());
+ s->prevTextBox()->setNextTextBox(s->nextTextBox());
if (m_lastTextBox == s)
m_lastTextBox = s->prevTextBox();
else
- s->nextTextBox()->setPreviousLineBox(s->prevTextBox());
+ s->nextTextBox()->setPreviousTextBox(s->prevTextBox());
s->destroy(renderArena());
return;
}
@@ -1086,7 +1168,7 @@ void RenderText::positionLineBox(InlineBox* box)
m_containsReversedText |= s->direction() == RTL;
}
-unsigned RenderText::width(unsigned from, unsigned len, int xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts) const
+unsigned RenderText::width(unsigned from, unsigned len, int xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
{
if (from >= textLength())
return 0;
@@ -1094,10 +1176,10 @@ unsigned RenderText::width(unsigned from, unsigned len, int xPos, bool firstLine
if (from + len > textLength())
len = textLength() - from;
- return width(from, len, style(firstLine)->font(), xPos, fallbackFonts);
+ return width(from, len, style(firstLine)->font(), xPos, fallbackFonts, glyphOverflow);
}
-unsigned RenderText::width(unsigned from, unsigned len, const Font& f, int xPos, HashSet<const SimpleFontData*>* fallbackFonts) const
+unsigned RenderText::width(unsigned from, unsigned len, const Font& f, int xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
{
ASSERT(from + len <= textLength());
if (!characters())
@@ -1107,18 +1189,19 @@ unsigned RenderText::width(unsigned from, unsigned len, const Font& f, int xPos,
if (&f == &style()->font()) {
if (!style()->preserveNewline() && !from && len == textLength()) {
if (fallbackFonts) {
- if (prefWidthsDirty() || !m_knownNotToUseFallbackFonts) {
- const_cast<RenderText*>(this)->calcPrefWidths(0, *fallbackFonts);
- if (fallbackFonts->isEmpty())
- m_knownNotToUseFallbackFonts = true;
+ ASSERT(glyphOverflow);
+ if (prefWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
+ const_cast<RenderText*>(this)->calcPrefWidths(0, *fallbackFonts, *glyphOverflow);
+ if (fallbackFonts->isEmpty() && !glyphOverflow->left && !glyphOverflow->right && !glyphOverflow->top && !glyphOverflow->bottom)
+ m_knownToHaveNoOverflowAndNoFallbackFonts = true;
}
w = m_maxWidth;
} else
w = maxPrefWidth();
} else
- w = widthFromCache(f, from, len, xPos, fallbackFonts);
+ w = widthFromCache(f, from, len, xPos, fallbackFonts, glyphOverflow);
} else
- w = f.width(TextRun(text()->characters() + from, len, allowTabs(), xPos), fallbackFonts);
+ w = f.width(TextRun(text()->characters() + from, len, allowTabs(), xPos), fallbackFonts, glyphOverflow);
return w;
}
@@ -1150,6 +1233,11 @@ IntRect RenderText::linesBoundingBox() const
IntRect RenderText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
{
RenderObject* cb = containingBlock();
+ // The containing block may be an ancestor of repaintContainer, but we need to do a repaintContainer-relative repaint.
+ if (repaintContainer && repaintContainer != cb) {
+ if (!cb->isDescendantOf(repaintContainer))
+ return repaintContainer->clippedOverflowRectForRepaint(repaintContainer);
+ }
return cb->clippedOverflowRectForRepaint(repaintContainer);
}
@@ -1245,7 +1333,7 @@ unsigned RenderText::caretMaxRenderedOffset() const
int RenderText::previousOffset(int current) const
{
- StringImpl* si = m_text.get();
+ StringImpl* si = m_text.impl();
TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length());
if (!iterator)
return current - 1;
@@ -1293,14 +1381,16 @@ inline bool isHangulLVT(UChar32 character)
int RenderText::previousOffsetForBackwardDeletion(int current) const
{
#if PLATFORM(MAC)
+ ASSERT(m_text);
+ StringImpl& text = *m_text.impl();
UChar32 character;
while (current > 0) {
- if (U16_IS_TRAIL((*m_text)[--current]))
+ if (U16_IS_TRAIL(text[--current]))
--current;
if (current < 0)
break;
- UChar32 character = m_text->characterStartingAt(current);
+ UChar32 character = text.characterStartingAt(current);
// We don't combine characters in Armenian ... Limbu range for backward deletion.
if ((character >= 0x0530) && (character < 0x1950))
@@ -1314,7 +1404,7 @@ int RenderText::previousOffsetForBackwardDeletion(int current) const
return current;
// Hangul
- character = m_text->characterStartingAt(current);
+ character = text.characterStartingAt(current);
if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) {
HangulState state;
HangulState initialState;
@@ -1330,7 +1420,7 @@ int RenderText::previousOffsetForBackwardDeletion(int current) const
initialState = state;
- while (current > 0 && ((character = m_text->characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) {
+ 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)
@@ -1368,7 +1458,7 @@ int RenderText::previousOffsetForBackwardDeletion(int current) const
int RenderText::nextOffset(int current) const
{
- StringImpl* si = m_text.get();
+ StringImpl* si = m_text.impl();
TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length());
if (!iterator)
return current + 1;