summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/rendering/RenderText.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/rendering/RenderText.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/core/rendering/RenderText.cpp245
1 files changed, 136 insertions, 109 deletions
diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderText.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderText.cpp
index b89ddc756ba..64fa967bd38 100644
--- a/chromium/third_party/WebKit/Source/core/rendering/RenderText.cpp
+++ b/chromium/third_party/WebKit/Source/core/rendering/RenderText.cpp
@@ -28,9 +28,9 @@
#include "core/accessibility/AXObjectCache.h"
#include "core/dom/Text.h"
#include "core/editing/TextIterator.h"
-#include "core/fetch/TextResourceDecoder.h"
#include "core/frame/FrameView.h"
#include "core/frame/Settings.h"
+#include "core/html/parser/TextResourceDecoder.h"
#include "core/rendering/AbstractInlineTextBox.h"
#include "core/rendering/EllipsisBox.h"
#include "core/rendering/InlineTextBox.h"
@@ -39,8 +39,12 @@
#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderView.h"
#include "core/rendering/break_lines.h"
+#include "platform/fonts/Character.h"
+#include "platform/fonts/FontCache.h"
#include "platform/geometry/FloatQuad.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"
@@ -64,7 +68,7 @@ class SecureTextTimer;
typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap;
static SecureTextTimerMap* gSecureTextTimers = 0;
-class SecureTextTimer : public TimerBase {
+class SecureTextTimer FINAL : public TimerBase {
public:
SecureTextTimer(RenderText* renderText)
: m_renderText(renderText)
@@ -76,13 +80,13 @@ public:
{
m_lastTypedCharacterOffset = lastTypedCharacterOffset;
if (Settings* settings = m_renderText->document().settings())
- startOneShot(settings->passwordEchoDurationInSeconds());
+ startOneShot(settings->passwordEchoDurationInSeconds(), FROM_HERE);
}
void invalidate() { m_lastTypedCharacterOffset = -1; }
unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; }
private:
- virtual void fired()
+ 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 */);
@@ -190,8 +194,8 @@ void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl
// 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 == StyleDifferenceLayout) {
- setNeedsLayoutAndPrefWidthsRecalc();
+ if (diff.needsFullLayout()) {
+ setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
m_knownToHaveNoOverflowAndNoFallbackFonts = false;
}
@@ -201,8 +205,11 @@ void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl
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();
+ newStyle->font().willUseFontData(text().characterStartingAt(0));
}
void RenderText::removeAndDestroyTextBoxes()
@@ -210,7 +217,7 @@ void RenderText::removeAndDestroyTextBoxes()
if (!documentBeingDestroyed()) {
if (firstTextBox()) {
if (isBR()) {
- RootInlineBox* next = firstTextBox()->root()->nextRootBox();
+ RootInlineBox* next = firstTextBox()->root().nextRootBox();
if (next)
next->markDirty();
}
@@ -362,11 +369,11 @@ void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, u
if (useSelectionHeight) {
LayoutRect selectionRect = box->localSelectionRect(start, end);
if (box->isHorizontal()) {
- r.setHeight(selectionRect.height());
- r.setY(selectionRect.y());
+ r.setHeight(selectionRect.height().toFloat());
+ r.setY(selectionRect.y().toFloat());
} else {
- r.setWidth(selectionRect.width());
- r.setX(selectionRect.x());
+ r.setWidth(selectionRect.width().toFloat());
+ r.setX(selectionRect.x().toFloat());
}
}
rects.append(localToAbsoluteQuad(r, 0, wasFixed).enclosingBoundingBox());
@@ -389,7 +396,7 @@ static IntRect ellipsisRectForBox(InlineTextBox* box, unsigned startPos, unsigne
return IntRect();
IntRect rect;
- if (EllipsisBox* ellipsis = box->root()->ellipsisBox()) {
+ if (EllipsisBox* ellipsis = box->root().ellipsisBox()) {
int ellipsisStartPosition = max<int>(startPos - box->start(), 0);
int ellipsisEndPosition = min<int>(endPos - box->start(), box->len());
@@ -445,11 +452,11 @@ void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start,
if (useSelectionHeight) {
LayoutRect selectionRect = box->localSelectionRect(start, end);
if (box->isHorizontal()) {
- r.setHeight(selectionRect.height());
- r.setY(selectionRect.y());
+ r.setHeight(selectionRect.height().toFloat());
+ r.setY(selectionRect.y().toFloat());
} else {
- r.setWidth(selectionRect.width());
- r.setX(selectionRect.x());
+ r.setWidth(selectionRect.width().toFloat());
+ r.setX(selectionRect.x().toFloat());
}
}
quads.append(localToAbsoluteQuad(r, 0, wasFixed));
@@ -461,27 +468,6 @@ void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start,
}
}
-InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const
-{
- // The text runs point to parts of the RenderText's m_text
- // (they don't include '\n')
- // Find the text run that includes the character at offset
- // and return pos, which is the position of the char in the run.
-
- if (!m_firstTextBox)
- return 0;
-
- InlineTextBox* s = m_firstTextBox;
- int off = s->len();
- while (offset > off && s->nextTextBox()) {
- s = s->nextTextBox();
- off = s->start() + s->len();
- }
- // we are now in the correct text run
- pos = (offset > off ? s->len() : s->len() - (off - offset) );
- return s;
-}
-
enum ShouldAffinityBeDownstream { AlwaysDownstream, AlwaysUpstream, UpstreamIfPositionIsNotAtStart };
static bool lineDirectionPointFitsInBox(int pointLineDirection, InlineTextBox* box, ShouldAffinityBeDownstream& shouldAffinityBeDownstream)
@@ -533,14 +519,13 @@ static PositionWithAffinity createPositionWithAffinityForBox(const InlineBox* bo
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);
+ 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(box->renderer());
ASSERT(offset >= 0);
if (offset && static_cast<unsigned>(offset) < box->len())
@@ -552,7 +537,7 @@ static PositionWithAffinity createPositionWithAffinityForBoxAfterAdjustingOffset
const InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak();
if ((prevBox && prevBox->bidiLevel() == box->bidiLevel())
- || box->renderer()->containingBlock()->style()->direction() == box->direction()) // FIXME: left on 12CBA
+ || box->renderer().containingBlock()->style()->direction() == box->direction()) // FIXME: left on 12CBA
return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
if (prevBox && prevBox->bidiLevel() > box->bidiLevel()) {
@@ -582,7 +567,7 @@ static PositionWithAffinity createPositionWithAffinityForBoxAfterAdjustingOffset
const InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak();
if ((nextBox && nextBox->bidiLevel() == box->bidiLevel())
- || box->renderer()->containingBlock()->style()->direction() == box->direction())
+ || box->renderer().containingBlock()->style()->direction() == box->direction())
return createPositionWithAffinityForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
// offset is on the right edge
@@ -625,17 +610,17 @@ PositionWithAffinity RenderText::positionForPoint(const LayoutPoint& point)
if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild() && !box->nextLeafChild()->isLineBreak())
box = box->nextTextBox();
- RootInlineBox* rootBox = box->root();
- LayoutUnit top = min(rootBox->selectionTop(), rootBox->lineTop());
+ RootInlineBox& rootBox = box->root();
+ LayoutUnit top = min(rootBox.selectionTop(), rootBox.lineTop());
if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirection == top)) {
- LayoutUnit bottom = rootBox->selectionBottom();
- if (rootBox->nextRootBox())
- bottom = min(bottom, rootBox->nextRootBox()->lineTop());
+ LayoutUnit bottom = rootBox.selectionBottom();
+ if (rootBox.nextRootBox())
+ bottom = min(bottom, rootBox.nextRootBox()->lineTop());
if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockDirection == bottom)) {
ShouldAffinityBeDownstream shouldAffinityBeDownstream;
if (lineDirectionPointFitsInBox(pointLineDirection, box, shouldAffinityBeDownstream))
- return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(box, box->offsetForPosition(pointLineDirection), shouldAffinityBeDownstream);
+ return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(box, box->offsetForPosition(pointLineDirection.toFloat()), shouldAffinityBeDownstream);
}
}
lastBox = box;
@@ -644,7 +629,7 @@ PositionWithAffinity RenderText::positionForPoint(const LayoutPoint& point)
if (lastBox) {
ShouldAffinityBeDownstream shouldAffinityBeDownstream;
lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityBeDownstream);
- return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastBox, lastBox->offsetForPosition(pointLineDirection) + lastBox->start(), shouldAffinityBeDownstream);
+ return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastBox, lastBox->offsetForPosition(pointLineDirection.toFloat()) + lastBox->start(), shouldAffinityBeDownstream);
}
return createPositionWithAffinity(0, DOWNSTREAM);
}
@@ -660,8 +645,8 @@ LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay
InlineTextBox* box = toInlineTextBox(inlineBox);
- int height = box->root()->selectionHeight();
- int top = box->root()->selectionTop();
+ 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);
@@ -673,13 +658,13 @@ LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay
left = roundf(left);
- float rootLeft = box->root()->logicalLeft();
- float rootRight = box->root()->logicalRight();
+ 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);
+ *extraWidthToEndOfLine = (box->root().logicalWidth() + rootLeft) - (left + 1);
RenderBlock* cb = containingBlock();
RenderStyle* cbStyle = cb->style();
@@ -687,7 +672,7 @@ LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay
float leftEdge;
float rightEdge;
leftEdge = min<float>(0, rootLeft);
- rightEdge = max<float>(cb->logicalWidth(), rootRight);
+ rightEdge = max<float>(cb->logicalWidth().toFloat(), rootRight);
bool rightAligned = false;
switch (cbStyle->textAlign()) {
@@ -720,7 +705,7 @@ LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay
return 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, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+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);
@@ -728,7 +713,7 @@ ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len
return combineText->combinedTextWidth(f);
}
- if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
+ if (f.isFixedPitch() && f.fontDescription().variant() == FontVariantNormal && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
float monospaceCharacterWidth = f.spaceWidth();
float w = 0;
bool isSpace;
@@ -755,18 +740,19 @@ ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len
isSpace = false;
}
if (isSpace && i > start)
- w += f.wordSpacing();
+ w += f.fontDescription().wordSpacing();
}
return w;
}
- TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, start, len, style());
+ TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, start, len, style(), textDirection);
run.setCharactersLength(textLength() - start);
ASSERT(run.charactersLength() >= run.length());
run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
run.setXPos(xPos);
+ FontCachePurgePreventer fontCachePurgePreventer;
return f.width(run, fallbackFonts, glyphOverflow);
}
@@ -775,7 +761,8 @@ void RenderText::trimmedPrefWidths(float leadWidth,
float& lastLineMinWidth, bool& hasBreakableEnd,
bool& hasBreakableChar, bool& hasBreak,
float& firstLineMaxWidth, float& lastLineMaxWidth,
- float& minWidth, float& maxWidth, bool& stripFrontSpaces)
+ float& minWidth, float& maxWidth, bool& stripFrontSpaces,
+ TextDirection direction)
{
bool collapseWhiteSpace = style()->collapseWhiteSpace();
if (!collapseWhiteSpace)
@@ -815,10 +802,10 @@ void RenderText::trimmedPrefWidths(float leadWidth,
const Font& font = style()->font(); // FIXME: This ignores first-line.
if (stripFrontSpaces) {
const UChar space = ' ';
- float spaceWidth = font.width(RenderBlockFlow::constructTextRun(this, font, &space, 1, style()));
+ float spaceWidth = font.width(RenderBlockFlow::constructTextRun(this, font, &space, 1, style(), direction));
maxWidth -= spaceWidth;
} else {
- maxWidth += font.wordSpacing();
+ maxWidth += font.fontDescription().wordSpacing();
}
}
@@ -839,7 +826,7 @@ void RenderText::trimmedPrefWidths(float leadWidth,
linelen++;
if (linelen) {
- lastLineMaxWidth = widthFromCache(f, i, linelen, leadWidth + lastLineMaxWidth, 0, 0);
+ lastLineMaxWidth = widthFromCache(f, i, linelen, leadWidth + lastLineMaxWidth, direction, 0, 0);
if (firstLine) {
firstLine = false;
leadWidth = 0;
@@ -886,10 +873,10 @@ void RenderText::computePreferredLogicalWidths(float leadWidth)
m_knownToHaveNoOverflowAndNoFallbackFonts = true;
}
-static inline float hyphenWidth(RenderText* renderer, const Font& font)
+static inline float hyphenWidth(RenderText* renderer, const Font& font, TextDirection direction)
{
RenderStyle* style = renderer->style();
- return font.width(RenderBlockFlow::constructTextRun(renderer, font, style->hyphenString().string(), style));
+ return font.width(RenderBlockFlow::constructTextRun(renderer, font, style->hyphenString().string(), style, direction));
}
void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
@@ -925,23 +912,47 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
bool firstLine = true;
int nextBreakable = -1;
int lastWordBoundary = 0;
+ float cachedWordTrailingSpaceWidth[2] = { 0, 0 }; // LTR, RTL
- // Non-zero only when kerning is enabled, in which case we measure words with their trailing
- // space, then subtract its width.
- float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(RenderBlockFlow::constructTextRun(this, f, &space, 1, styleToUse)) + wordSpacing : 0;
-
- // If automatic hyphenation is allowed, we keep track of the width of the widest word (or word
- // fragment) encountered so far, and only try hyphenating words that are wider.
- float maxWordWidth = numeric_limits<float>::max();
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(LTR, false);
+ status.last = status.lastStrong = WTF::Unicode::OtherNeutral;
+ 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);
- bool previousCharacterIsSpace = isSpace;
+ 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 == '\n') {
if (styleToUse->preserveNewline()) {
@@ -979,7 +990,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
lastWordBoundary++;
continue;
} else if (c == softHyphen) {
- currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
+ currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
if (firstGlyphLeftOverflow < 0)
firstGlyphLeftOverflow = glyphOverflow.left;
lastWordBoundary = i + 1;
@@ -1002,20 +1013,32 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
}
}
+ // Terminate word boundary at bidi run boundary.
+ if (run)
+ j = min(j, run->stop() + 1);
int wordLen = j - i;
if (wordLen) {
bool isSpace = (j < len) && c == ' ';
+
+ // 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(RenderBlockFlow::constructTextRun(this, f, &space, 1, styleToUse, textDirection)) + wordSpacing;
+ wordTrailingSpaceWidth = cachedWordTrailingSpaceWidth[textDirection];
+ }
+
float w;
if (wordTrailingSpaceWidth && isSpace)
- w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth;
+ w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth;
else {
- w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
+ w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
if (c == softHyphen)
- currMinWidth += hyphenWidth(this, f);
+ currMinWidth += hyphenWidth(this, f, textDirection);
}
- maxWordWidth = max(maxWordWidth, w);
-
if (firstGlyphLeftOverflow < 0)
firstGlyphLeftOverflow = glyphOverflow.left;
currMinWidth += w;
@@ -1023,7 +1046,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
if (lastWordBoundary == i)
currMaxWidth += w;
else
- currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow);
+ currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow);
lastWordBoundary = j;
}
@@ -1074,7 +1097,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
m_maxWidth = currMaxWidth;
currMaxWidth = 0;
} else {
- TextRun run = RenderBlockFlow::constructTextRun(this, f, this, i, 1, styleToUse);
+ TextRun run = RenderBlockFlow::constructTextRun(this, f, this, i, 1, styleToUse, textDirection);
run.setCharactersLength(len - i);
ASSERT(run.charactersLength() >= run.length());
run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize());
@@ -1088,6 +1111,8 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
lastWordBoundary++;
}
}
+ if (run)
+ bidiResolver.runs().deleteRuns();
if (firstGlyphLeftOverflow > 0)
glyphOverflow.left = firstGlyphLeftOverflow;
@@ -1172,16 +1197,12 @@ void RenderText::setSelectionState(SelectionState state)
for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
if (box->isSelected(startPos, endPos)) {
- RootInlineBox* root = box->root();
- if (root)
- root->setHasSelectedChildren(true);
+ box->root().setHasSelectedChildren(true);
}
}
} else {
for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- RootInlineBox* root = box->root();
- if (root)
- root->setHasSelectedChildren(state == SelectionInside);
+ box->root().setHasSelectedChildren(state == SelectionInside);
}
}
}
@@ -1217,7 +1238,7 @@ void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset,
// Text run is entirely after the affected range.
if (curr->start() > end) {
curr->offsetRun(delta);
- RootInlineBox* root = curr->root();
+ RootInlineBox* root = &curr->root();
if (!firstRootBox) {
firstRootBox = root;
// The affected area was in between two runs. Go ahead and mark the root box of
@@ -1251,7 +1272,7 @@ void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset,
firstRootBox = prev;
} else if (lastTextBox()) {
ASSERT(!lastRootBox);
- firstRootBox = lastTextBox()->root();
+ firstRootBox = &lastTextBox()->root();
firstRootBox->markDirty();
dirtiedLines = true;
}
@@ -1385,7 +1406,11 @@ void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
return;
setTextInternal(text);
- setNeedsLayoutAndPrefWidthsRecalc();
+ // If preferredLogicalWidthsDirty() of an orphan child is true, RenderObjectChildList::
+ // insertChildNode() fails to set true to owner. To avoid that, we call
+ // setNeedsLayoutAndPrefWidthsRecalc() only if this RenderText has parent.
+ if (parent())
+ setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
m_knownToHaveNoOverflowAndNoFallbackFonts = false;
if (AXObjectCache* cache = document().existingAXObjectCache())
@@ -1405,7 +1430,7 @@ void RenderText::dirtyLineBoxes(bool fullLayout)
InlineTextBox* RenderText::createTextBox()
{
- return new InlineTextBox(this);
+ return new InlineTextBox(*this);
}
InlineTextBox* RenderText::createInlineTextBox()
@@ -1429,7 +1454,7 @@ void RenderText::positionLineBox(InlineBox* box)
// FIXME: should not be needed!!!
if (!s->len()) {
// We want the box to be destroyed.
- s->remove();
+ s->remove(DontMarkLineBoxes);
if (m_firstTextBox == s)
m_firstTextBox = s->nextTextBox();
else
@@ -1445,7 +1470,7 @@ void RenderText::positionLineBox(InlineBox* box)
m_containsReversedText |= !s->isLeftToRightDirection();
}
-float RenderText::width(unsigned from, unsigned len, float xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+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;
@@ -1453,10 +1478,10 @@ float RenderText::width(unsigned from, unsigned len, float xPos, bool firstLine,
if (from + len > textLength())
len = textLength() - from;
- return width(from, len, style(firstLine)->font(), xPos, fallbackFonts, glyphOverflow);
+ return width(from, len, style(firstLine)->font(), xPos, textDirection, fallbackFonts, glyphOverflow);
}
-float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+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())
@@ -1473,12 +1498,14 @@ float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos,
m_knownToHaveNoOverflowAndNoFallbackFonts = true;
}
w = m_maxWidth;
- } else
+ } else {
w = maxLogicalWidth();
- } else
- w = widthFromCache(f, from, len, xPos, fallbackFonts, glyphOverflow);
+ }
+ } else {
+ w = widthFromCache(f, from, len, xPos, textDirection, fallbackFonts, glyphOverflow);
+ }
} else {
- TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, from, len, style());
+ TextRun run = RenderBlockFlow::constructTextRun(const_cast<RenderText*>(this), f, this, from, len, style(), textDirection);
run.setCharactersLength(textLength() - from);
ASSERT(run.charactersLength() >= run.length());
@@ -1542,7 +1569,7 @@ LayoutRect RenderText::linesVisualOverflowBoundingBox() const
return rect;
}
-LayoutRect RenderText::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
+LayoutRect RenderText::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const
{
RenderObject* rendererToRepaint = containingBlock();
@@ -1551,14 +1578,14 @@ LayoutRect RenderText::clippedOverflowRectForRepaint(const RenderLayerModelObjec
if (enclosingLayerRenderer != rendererToRepaint && !rendererToRepaint->isDescendantOf(enclosingLayerRenderer))
rendererToRepaint = enclosingLayerRenderer;
- // The renderer we chose to repaint may be an ancestor of repaintContainer, but we need to do a repaintContainer-relative repaint.
- if (repaintContainer && repaintContainer != rendererToRepaint && !rendererToRepaint->isDescendantOf(repaintContainer))
- return repaintContainer->clippedOverflowRectForRepaint(repaintContainer);
+ // The renderer we chose to repaint may be an ancestor of paintInvalidationContainer, but we need to do a paintInvalidationContainer-relative repaint.
+ if (paintInvalidationContainer && paintInvalidationContainer != rendererToRepaint && !rendererToRepaint->isDescendantOf(paintInvalidationContainer))
+ return paintInvalidationContainer->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer);
- return rendererToRepaint->clippedOverflowRectForRepaint(repaintContainer);
+ return rendererToRepaint->clippedOverflowRectForPaintInvalidation(paintInvalidationContainer);
}
-LayoutRect RenderText::selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent)
+LayoutRect RenderText::selectionRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, bool clipToVisibleContent)
{
ASSERT(!needsLayout());
@@ -1593,12 +1620,12 @@ LayoutRect RenderText::selectionRectForRepaint(const RenderLayerModelObject* rep
}
if (clipToVisibleContent)
- computeRectForRepaint(repaintContainer, rect);
+ mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect);
else {
if (cb->hasColumns())
cb->adjustRectForColumns(rect);
- rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox();
+ rect = localToContainerQuad(FloatRect(rect), paintInvalidationContainer).enclosingBoundingBox();
}
return rect;
@@ -1809,7 +1836,7 @@ bool RenderText::computeCanUseSimpleFontCodePath() const
{
if (isAllASCII() || m_text.is8Bit())
return true;
- return Font::characterRangeCodePath(characters16(), length()) == Font::Simple;
+ return Character::characterRangeCodePath(characters16(), length()) == SimplePath;
}
#ifndef NDEBUG