summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering/RenderBlockLineLayout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/rendering/RenderBlockLineLayout.cpp')
-rw-r--r--WebCore/rendering/RenderBlockLineLayout.cpp127
1 files changed, 110 insertions, 17 deletions
diff --git a/WebCore/rendering/RenderBlockLineLayout.cpp b/WebCore/rendering/RenderBlockLineLayout.cpp
index d703fb2..3cd944b 100644
--- a/WebCore/rendering/RenderBlockLineLayout.cpp
+++ b/WebCore/rendering/RenderBlockLineLayout.cpp
@@ -33,6 +33,7 @@
#include "RenderLayer.h"
#include "RenderListMarker.h"
#include "RenderView.h"
+#include "Settings.h"
#include "TrailingFloatsRootInlineBox.h"
#include "break_lines.h"
#include <wtf/AlwaysInline.h>
@@ -48,6 +49,7 @@
#endif // ANDROID_LAYOUT
#if ENABLE(SVG)
+#include "RenderSVGInlineText.h"
#include "SVGRootInlineBox.h"
#endif
@@ -597,6 +599,9 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
Vector<FloatWithRect> floats;
bool hasInlineChild = false;
while (o) {
+ if (!hasInlineChild && o->isInline())
+ hasInlineChild = true;
+
if (o->isReplaced() || o->isFloating() || o->isPositioned()) {
RenderBox* box = toRenderBox(o);
@@ -609,6 +614,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
if (o->isPositioned())
o->containingBlock()->insertPositionedObject(box);
+<<<<<<< HEAD
else {
#ifdef ANDROID_LAYOUT
// ignore text wrap for textField or menuList
@@ -629,6 +635,13 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
// the document is the DOM node associated with this RenderObject.
RefPtr<Node> protector(o->isAnonymous() ? o->document() : o->node());
#endif
+=======
+ else if (o->isFloating())
+ floats.append(FloatWithRect(box));
+ else if (fullLayout || o->needsLayout()) {
+ // Replaced elements
+ toRenderBox(o)->dirtyLineBoxes(fullLayout);
+>>>>>>> webkit.org at r67908
o->layoutIfNeeded();
#if defined(ANDROID_FLATTEN_IFRAME) || defined(ANDROID_FLATTEN_FRAMESET)
// Ensure that the renderer still exists. If it's gone away we will crash pretty
@@ -639,7 +652,6 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
#endif
}
} else if (o->isText() || (o->isRenderInline() && !endOfInline)) {
- hasInlineChild = true;
if (fullLayout || o->selfNeedsLayout())
dirtyLineBoxesForRenderer(o, fullLayout);
o->setNeedsLayout(false);
@@ -717,7 +729,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
unsigned floatIndex;
bool firstLine = true;
bool previousLineBrokeCleanly = true;
- RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex);
+ RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex,
+ useRepaintBounds, repaintTop, repaintBottom);
if (fullLayout && hasInlineChild && !selfNeedsLayout()) {
setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like
@@ -745,9 +758,11 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, endLineYPos);
if (startLine) {
- useRepaintBounds = true;
- repaintTop = height();
- repaintBottom = height();
+ if (!useRepaintBounds) {
+ useRepaintBounds = true;
+ repaintTop = height();
+ repaintBottom = height();
+ }
RenderArena* arena = renderArena();
RootInlineBox* box = startLine;
while (box) {
@@ -782,6 +797,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
bool checkForFloatsFromLastLine = false;
bool isLineEmpty = true;
+ bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
while (!end.atEnd()) {
// FIXME: Is this check necessary before the first iteration or can it be moved to the end?
@@ -794,7 +810,10 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
EClear clear = CNONE;
bool hyphenated;
- end = findNextLineBreak(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, hyphenated, &clear);
+
+ InlineIterator oldEnd = end;
+ FloatingObject* lastFloatFromPreviousLine = m_floatingObjects ? m_floatingObjects->last() : 0;
+ end = findNextLineBreak(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, hyphenated, &clear, lastFloatFromPreviousLine);
if (resolver.position().atEnd()) {
resolver.deleteRuns();
checkForFloatsFromLastLine = true;
@@ -859,6 +878,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
// inline flow boxes.
RootInlineBox* lineBox = 0;
+ int oldHeight = height();
if (resolver.runCount()) {
if (hyphenated)
resolver.logicallyLastRun()->m_hasHyphen = true;
@@ -909,6 +929,29 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
repaintTop = min(repaintTop, lineBox->topVisibleOverflow());
repaintBottom = max(repaintBottom, lineBox->bottomVisibleOverflow());
}
+
+ if (paginated) {
+ int adjustment = 0;
+ adjustLinePositionForPagination(lineBox, adjustment);
+ if (adjustment) {
+ int oldLineWidth = lineWidth(oldHeight, firstLine);
+ lineBox->adjustPosition(0, adjustment);
+ if (useRepaintBounds) // This can only be a positive adjustment, so no need to update repaintTop.
+ repaintBottom = max(repaintBottom, lineBox->bottomVisibleOverflow());
+
+ if (lineWidth(oldHeight + adjustment, firstLine) != oldLineWidth) {
+ // We have to delete this line, remove all floats that got added, and let line layout re-run.
+ lineBox->deleteLine(renderArena());
+ removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldHeight);
+ setHeight(oldHeight + adjustment);
+ resolver.setPosition(oldEnd);
+ end = oldEnd;
+ continue;
+ }
+
+ setHeight(lineBox->blockHeight());
+ }
+ }
}
firstLine = false;
@@ -943,6 +986,10 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
int delta = height() - endLineYPos;
for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) {
line->attachLine();
+ if (paginated) {
+ delta -= line->paginationStrut();
+ adjustLinePositionForPagination(line, delta);
+ }
if (delta) {
repaintTop = min(repaintTop, line->topVisibleOverflow() + min(delta, 0));
repaintBottom = max(repaintBottom, line->bottomVisibleOverflow() + max(delta, 0));
@@ -1023,20 +1070,44 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i
}
RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly,
- InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats)
+ InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats,
+ bool& useRepaintBounds, int& repaintTop, int& repaintBottom)
{
RootInlineBox* curr = 0;
RootInlineBox* last = 0;
bool dirtiedByFloat = false;
if (!fullLayout) {
+ // Paginate all of the clean lines.
+ bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
+ int paginationDelta = 0;
size_t floatIndex = 0;
for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) {
+ if (paginated) {
+ paginationDelta -= curr->paginationStrut();
+ adjustLinePositionForPagination(curr, paginationDelta);
+ if (paginationDelta) {
+ if (containsFloats() || !floats.isEmpty()) {
+ // FIXME: Do better eventually. For now if we ever shift because of pagination and floats are present just go to a full layout.
+ fullLayout = true;
+ break;
+ }
+
+ if (!useRepaintBounds)
+ useRepaintBounds = true;
+
+ repaintTop = min(repaintTop, curr->topVisibleOverflow() + min(paginationDelta, 0));
+ repaintBottom = max(repaintBottom, curr->bottomVisibleOverflow() + max(paginationDelta, 0));
+ curr->adjustPosition(0, paginationDelta);
+ }
+ }
+
if (Vector<RenderBox*>* cleanLineFloats = curr->floatsPtr()) {
Vector<RenderBox*>::iterator end = cleanLineFloats->end();
for (Vector<RenderBox*>::iterator o = cleanLineFloats->begin(); o != end; ++o) {
RenderBox* f = *o;
- IntSize newSize(f->width() + f->marginLeft() +f->marginRight(), f->height() + f->marginTop() + f->marginBottom());
+ f->layoutIfNeeded();
+ IntSize newSize(f->width() + f->marginLeft() + f->marginRight(), f->height() + f->marginTop() + f->marginBottom());
ASSERT(floatIndex < floats.size());
if (floats[floatIndex].object != f) {
// A new float has been inserted before this line or before its last known float.
@@ -1359,14 +1430,14 @@ void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator, bool isLineEm
}
}
-int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly)
+int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly,
+ FloatingObject* lastFloatFromPreviousLine)
{
int availableWidth = lineWidth(height(), firstLine);
while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), isLineEmpty, previousLineBrokeCleanly)) {
RenderObject* object = resolver.position().obj;
if (object->isFloating()) {
- insertFloatingObject(toRenderBox(object));
- positionNewFloats();
+ positionNewFloatOnLine(insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine);
availableWidth = lineWidth(height(), firstLine);
} else if (object->isPositioned()) {
// FIXME: The math here is actually not really right. It's a best-guess approximation that
@@ -1450,7 +1521,13 @@ static void tryHyphenating(RenderText* text, const Font& font, const AtomicStrin
const AtomicString& hyphenString = text->style()->hyphenString();
int hyphenWidth = font.width(TextRun(hyphenString.characters(), hyphenString.length()));
- unsigned prefixLength = font.offsetForPosition(TextRun(text->characters() + lastSpace, pos - lastSpace, !collapseWhiteSpace, xPos + lastSpaceWordSpacing), availableWidth - xPos - hyphenWidth - lastSpaceWordSpacing, false);
+ int maxPrefixWidth = availableWidth - xPos - hyphenWidth - lastSpaceWordSpacing;
+ // If the maximum width available for the prefix before the hyphen is small, then it is very unlikely
+ // that an hyphenation opportunity exists, so do not bother to look for it.
+ if (maxPrefixWidth <= font.pixelSize() * 5 / 4)
+ return;
+
+ unsigned prefixLength = font.offsetForPosition(TextRun(text->characters() + lastSpace, pos - lastSpace, !collapseWhiteSpace, xPos + lastSpaceWordSpacing), maxPrefixWidth, false);
if (!prefixLength)
return;
@@ -1472,14 +1549,14 @@ static void tryHyphenating(RenderText* text, const Font& font, const AtomicStrin
}
InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly,
- bool& hyphenated, EClear* clear)
+ bool& hyphenated, EClear* clear, FloatingObject* lastFloatFromPreviousLine)
{
ASSERT(resolver.position().block == this);
bool appliedStartWidth = resolver.position().pos > 0;
LineMidpointState& lineMidpointState = resolver.midpointState();
- int width = skipLeadingWhitespace(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly);
+ int width = skipLeadingWhitespace(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, lastFloatFromPreviousLine);
int w = 0;
int tmpW = 0;
@@ -1564,12 +1641,12 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
// add to special objects...
if (o->isFloating()) {
RenderBox* floatBox = toRenderBox(o);
- insertFloatingObject(floatBox);
+ FloatingObject* f = insertFloatingObject(floatBox);
// check if it fits in the current line.
// If it does, position it now, otherwise, position
// it after moving to next line (in newLine() func)
if (floatsFitOnLine && floatBox->width() + floatBox->marginLeft() + floatBox->marginRight() + w + tmpW <= width) {
- positionNewFloats();
+ positionNewFloatOnLine(f, lastFloatFromPreviousLine);
width = lineWidth(height(), firstLine);
} else
floatsFitOnLine = false;
@@ -1681,6 +1758,10 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
RenderText* t = toRenderText(o);
+#if ENABLE(SVG)
+ bool isSVGText = t->isSVGInlineText();
+#endif
+
int strlen = t->textLength();
int len = strlen - pos;
const UChar* str = t->characters();
@@ -1765,7 +1846,19 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
}
continue;
}
-
+
+#if ENABLE(SVG)
+ if (isSVGText) {
+ RenderSVGInlineText* svgInlineText = static_cast<RenderSVGInlineText*>(t);
+ if (pos > 0) {
+ if (svgInlineText->characterStartsNewTextChunk(pos)) {
+ addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1));
+ addMidpoint(lineMidpointState, InlineIterator(0, o, pos));
+ }
+ }
+ }
+#endif
+
bool applyWordSpacing = false;
currentCharacterIsWS = currentCharacterIsSpace || (breakNBSP && c == noBreakSpace);