summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-09-29 17:32:26 +0100
committerSteve Block <steveblock@google.com>2010-09-29 17:35:08 +0100
commit68513a70bcd92384395513322f1b801e7bf9c729 (patch)
tree161b50f75a5921d61731bb25e730005994fcec85 /WebCore/rendering
parentfd5c6425ce58eb75211be7718d5dee960842a37e (diff)
downloadexternal_webkit-68513a70bcd92384395513322f1b801e7bf9c729.zip
external_webkit-68513a70bcd92384395513322f1b801e7bf9c729.tar.gz
external_webkit-68513a70bcd92384395513322f1b801e7bf9c729.tar.bz2
Merge WebKit at r67908: Initial merge by Git
Change-Id: I43a553e7b3299b28cb6ee8aa035ed70fe342b972
Diffstat (limited to 'WebCore/rendering')
-rw-r--r--WebCore/rendering/ColumnInfo.h54
-rw-r--r--WebCore/rendering/LayoutState.cpp75
-rw-r--r--WebCore/rendering/LayoutState.h25
-rw-r--r--WebCore/rendering/MediaControlElements.cpp2
-rw-r--r--WebCore/rendering/RenderBlock.cpp891
-rw-r--r--WebCore/rendering/RenderBlock.h152
-rw-r--r--WebCore/rendering/RenderBlockLineLayout.cpp127
-rw-r--r--WebCore/rendering/RenderBox.cpp30
-rw-r--r--WebCore/rendering/RenderBox.h8
-rw-r--r--WebCore/rendering/RenderBoxModelObject.cpp44
-rw-r--r--WebCore/rendering/RenderBoxModelObject.h4
-rw-r--r--WebCore/rendering/RenderEmbeddedObject.cpp6
-rw-r--r--WebCore/rendering/RenderFileUploadControl.cpp4
-rw-r--r--WebCore/rendering/RenderFlexibleBox.cpp234
-rw-r--r--WebCore/rendering/RenderFlexibleBox.h7
-rw-r--r--WebCore/rendering/RenderImage.cpp27
-rw-r--r--WebCore/rendering/RenderImage.h4
-rw-r--r--WebCore/rendering/RenderInline.cpp4
-rw-r--r--WebCore/rendering/RenderLayer.cpp12
-rw-r--r--WebCore/rendering/RenderLayerBacking.cpp12
-rwxr-xr-x[-rw-r--r--]WebCore/rendering/RenderLayerCompositor.cpp30
-rwxr-xr-x[-rw-r--r--]WebCore/rendering/RenderLayerCompositor.h2
-rw-r--r--WebCore/rendering/RenderLineBoxList.cpp6
-rw-r--r--WebCore/rendering/RenderMediaControls.cpp125
-rw-r--r--WebCore/rendering/RenderMediaControls.h1
-rw-r--r--WebCore/rendering/RenderObject.h10
-rw-r--r--WebCore/rendering/RenderReplaced.cpp72
-rw-r--r--WebCore/rendering/RenderReplaced.h9
-rw-r--r--WebCore/rendering/RenderSVGInline.h1
-rw-r--r--WebCore/rendering/RenderSVGInlineText.cpp41
-rw-r--r--WebCore/rendering/RenderSVGInlineText.h10
-rw-r--r--WebCore/rendering/RenderSVGResourceFilter.cpp15
-rw-r--r--WebCore/rendering/RenderSVGText.cpp4
-rw-r--r--WebCore/rendering/RenderSlider.cpp2
-rw-r--r--WebCore/rendering/RenderTable.cpp8
-rw-r--r--WebCore/rendering/RenderTableCell.cpp109
-rw-r--r--WebCore/rendering/RenderTableRow.cpp5
-rw-r--r--WebCore/rendering/RenderTableSection.cpp36
-rw-r--r--WebCore/rendering/RenderText.cpp58
-rw-r--r--WebCore/rendering/RenderText.h5
-rw-r--r--WebCore/rendering/RenderTextFragment.h15
-rw-r--r--WebCore/rendering/RenderThemeWin.cpp43
-rw-r--r--WebCore/rendering/RenderThemeWin.h9
-rw-r--r--WebCore/rendering/RenderThemeWinCE.cpp (renamed from WebCore/rendering/RenderThemeWince.cpp)98
-rw-r--r--WebCore/rendering/RenderThemeWinCE.h (renamed from WebCore/rendering/RenderThemeWince.h)12
-rw-r--r--WebCore/rendering/RenderVideo.cpp46
-rw-r--r--WebCore/rendering/RenderVideo.h3
-rw-r--r--WebCore/rendering/RenderView.cpp71
-rw-r--r--WebCore/rendering/RenderView.h127
-rw-r--r--WebCore/rendering/RootInlineBox.h6
-rw-r--r--WebCore/rendering/style/RenderStyle.cpp184
-rw-r--r--WebCore/rendering/style/RenderStyle.h48
-rw-r--r--WebCore/rendering/style/RenderStyleConstants.h5
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutAttributes.cpp100
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutAttributes.h89
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutBuilder.cpp304
-rw-r--r--WebCore/rendering/svg/SVGTextLayoutBuilder.h67
57 files changed, 2608 insertions, 890 deletions
diff --git a/WebCore/rendering/ColumnInfo.h b/WebCore/rendering/ColumnInfo.h
index 883287b..5e6f619 100644
--- a/WebCore/rendering/ColumnInfo.h
+++ b/WebCore/rendering/ColumnInfo.h
@@ -36,6 +36,12 @@ public:
ColumnInfo()
: m_desiredColumnWidth(0)
, m_desiredColumnCount(1)
+ , m_columnCount(1)
+ , m_columnHeight(0)
+ , m_minimumColumnHeight(0)
+ , m_forcedBreaks(0)
+ , m_maximumDistanceBetweenForcedBreaks(0)
+ , m_forcedBreakOffset(0)
{ }
int desiredColumnWidth() const { return m_desiredColumnWidth; }
@@ -44,19 +50,51 @@ public:
unsigned desiredColumnCount() const { return m_desiredColumnCount; }
void setDesiredColumnCount(unsigned count) { m_desiredColumnCount = count; }
- // Encapsulated for the future where we can avoid storing the rects and just compute them dynamically.
- size_t columnCount() const { return m_columnRects.size(); }
- const IntRect& columnRectAt(size_t i) const { return m_columnRects[i]; }
+ unsigned columnCount() const { return m_columnCount; }
+ int columnHeight() const { return m_columnHeight; }
- void clearColumns() { m_columnRects.clear(); }
+ // Set our count and height. This is enough info for a RenderBlock to compute page rects
+ // dynamically.
+ void setColumnCountAndHeight(int count, int height)
+ {
+ m_columnCount = count;
+ m_columnHeight = height;
+ }
+ void setColumnHeight(int height) { m_columnHeight = height; }
+
+ void updateMinimumColumnHeight(int height) { m_minimumColumnHeight = std::max(height, m_minimumColumnHeight); }
+ int minimumColumnHeight() const { return m_minimumColumnHeight; }
+
+ int forcedBreaks() const { return m_forcedBreaks; }
+ int forcedBreakOffset() const { return m_forcedBreakOffset; }
+ int maximumDistanceBetweenForcedBreaks() const { return m_maximumDistanceBetweenForcedBreaks; }
+ void clearForcedBreaks()
+ {
+ m_forcedBreaks = 0;
+ m_maximumDistanceBetweenForcedBreaks = 0;
+ m_forcedBreakOffset = 0;
+ }
+ void addForcedBreak(int offsetFromFirstPage)
+ {
+ ASSERT(!m_columnHeight);
+ int distanceFromLastBreak = offsetFromFirstPage - m_forcedBreakOffset;
+ if (!distanceFromLastBreak)
+ return;
+ m_forcedBreaks++;
+ m_maximumDistanceBetweenForcedBreaks = std::max(m_maximumDistanceBetweenForcedBreaks, distanceFromLastBreak);
+ m_forcedBreakOffset = offsetFromFirstPage;
+ }
- // FIXME: Will go away once we don't use the Vector.
- void addColumnRect(const IntRect& rect) { m_columnRects.append(rect); }
-
private:
int m_desiredColumnWidth;
unsigned m_desiredColumnCount;
- Vector<IntRect> m_columnRects;
+
+ unsigned m_columnCount;
+ int m_columnHeight;
+ int m_minimumColumnHeight;
+ int m_forcedBreaks; // FIXME: We will ultimately need to cache more information to balance around forced breaks properly.
+ int m_maximumDistanceBetweenForcedBreaks;
+ int m_forcedBreakOffset;
};
}
diff --git a/WebCore/rendering/LayoutState.cpp b/WebCore/rendering/LayoutState.cpp
index 18c3da7..0d81b15 100644
--- a/WebCore/rendering/LayoutState.cpp
+++ b/WebCore/rendering/LayoutState.cpp
@@ -26,6 +26,7 @@
#include "config.h"
#include "LayoutState.h"
+#include "ColumnInfo.h"
#include "RenderArena.h"
#include "RenderInline.h"
#include "RenderLayer.h"
@@ -33,8 +34,9 @@
namespace WebCore {
-LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize& offset)
- : m_next(prev)
+LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize& offset, int pageHeight, ColumnInfo* columnInfo)
+ : m_columnInfo(columnInfo)
+ , m_next(prev)
#ifndef NDEBUG
, m_renderer(renderer)
#endif
@@ -45,43 +47,67 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const IntSize&
if (fixed) {
// FIXME: This doesn't work correctly with transforms.
FloatPoint fixedOffset = renderer->view()->localToAbsolute(FloatPoint(), true);
- m_offset = IntSize(fixedOffset.x(), fixedOffset.y()) + offset;
+ m_paintOffset = IntSize(fixedOffset.x(), fixedOffset.y()) + offset;
} else
- m_offset = prev->m_offset + offset;
+ m_paintOffset = prev->m_paintOffset + offset;
- if (renderer->isRelPositioned()) {
- if (renderer->hasLayer())
- m_offset += renderer->layer()->relativePositionOffset();
- } else if (renderer->isPositioned() && !fixed) {
+ if (renderer->isPositioned() && !fixed) {
if (RenderObject* container = renderer->container()) {
if (container->isRelPositioned() && container->isRenderInline())
- m_offset += toRenderInline(container)->relativePositionedInlineOffset(renderer);
+ m_paintOffset += toRenderInline(container)->relativePositionedInlineOffset(renderer);
}
}
+ m_layoutOffset = m_paintOffset;
+
+ if (renderer->isRelPositioned() && renderer->hasLayer())
+ m_paintOffset += renderer->layer()->relativePositionOffset();
+
m_clipped = !fixed && prev->m_clipped;
if (m_clipped)
m_clipRect = prev->m_clipRect;
if (renderer->hasOverflowClip()) {
RenderLayer* layer = renderer->layer();
- IntRect clipRect(toPoint(m_offset) + renderer->view()->layoutDelta(), layer->size());
+ IntRect clipRect(toPoint(m_paintOffset) + renderer->view()->layoutDelta(), layer->size());
if (m_clipped)
m_clipRect.intersect(clipRect);
else {
m_clipRect = clipRect;
m_clipped = true;
}
- m_offset -= layer->scrolledContentOffset();
+
+ m_paintOffset -= layer->scrolledContentOffset();
}
- m_layoutDelta = m_next->m_layoutDelta;
+ // If we establish a new page height, then cache the offset to the top of the first page.
+ // We can compare this later on to figure out what part of the page we're actually on,
+ if (pageHeight || m_columnInfo) {
+ m_pageHeight = pageHeight;
+ m_pageOffset = IntSize(m_layoutOffset.width() + renderer->borderLeft() + renderer->paddingLeft(),
+ m_layoutOffset.height() + renderer->borderTop() + renderer->paddingTop());
+ } else {
+ // If we don't establish a new page height, then propagate the old page height and offset down.
+ m_pageHeight = m_next->m_pageHeight;
+ m_pageOffset = m_next->m_pageOffset;
+
+ // Disable pagination for objects we don't support. For now this includes overflow:scroll/auto and inline blocks.
+ if (renderer->isReplaced() || renderer->scrollsOverflow())
+ m_pageHeight = 0;
+ }
+
+ if (!m_columnInfo)
+ m_columnInfo = m_next->m_columnInfo;
+ m_layoutDelta = m_next->m_layoutDelta;
+
// FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present.
}
LayoutState::LayoutState(RenderObject* root)
: m_clipped(false)
+ , m_pageHeight(0)
+ , m_columnInfo(0)
, m_next(0)
#ifndef NDEBUG
, m_renderer(root)
@@ -89,13 +115,13 @@ LayoutState::LayoutState(RenderObject* root)
{
RenderObject* container = root->container();
FloatPoint absContentPoint = container->localToAbsolute(FloatPoint(), false, true);
- m_offset = IntSize(absContentPoint.x(), absContentPoint.y());
+ m_paintOffset = IntSize(absContentPoint.x(), absContentPoint.y());
if (container->hasOverflowClip()) {
RenderLayer* layer = toRenderBoxModelObject(container)->layer();
m_clipped = true;
- m_clipRect = IntRect(toPoint(m_offset), layer->size());
- m_offset -= layer->scrolledContentOffset();
+ m_clipRect = IntRect(toPoint(m_paintOffset), layer->size());
+ m_paintOffset -= layer->scrolledContentOffset();
}
}
@@ -126,4 +152,23 @@ void LayoutState::operator delete(void* ptr, size_t sz)
*(size_t*)ptr = sz;
}
+void LayoutState::clearPaginationInformation()
+{
+ m_pageHeight = m_next->m_pageHeight;
+ m_pageOffset = m_next->m_pageOffset;
+ m_columnInfo = m_next->m_columnInfo;
+}
+
+int LayoutState::pageY(int childY) const
+{
+ return m_layoutOffset.height() + childY - m_pageOffset.height();
+}
+
+void LayoutState::addForcedColumnBreak(int childY)
+{
+ if (!m_columnInfo || m_columnInfo->columnHeight())
+ return;
+ m_columnInfo->addForcedBreak(pageY(childY));
+}
+
} // namespace WebCore
diff --git a/WebCore/rendering/LayoutState.h b/WebCore/rendering/LayoutState.h
index 2f040c8..ca4cbfb 100644
--- a/WebCore/rendering/LayoutState.h
+++ b/WebCore/rendering/LayoutState.h
@@ -32,6 +32,7 @@
namespace WebCore {
+class ColumnInfo;
class RenderArena;
class RenderBox;
class RenderObject;
@@ -40,6 +41,8 @@ class LayoutState : public Noncopyable {
public:
LayoutState()
: m_clipped(false)
+ , m_pageHeight(0)
+ , m_columnInfo(0)
, m_next(0)
#ifndef NDEBUG
, m_renderer(0)
@@ -47,7 +50,7 @@ public:
{
}
- LayoutState(LayoutState*, RenderBox*, const IntSize& offset);
+ LayoutState(LayoutState*, RenderBox*, const IntSize& offset, int pageHeight, ColumnInfo*);
LayoutState(RenderObject*);
void destroy(RenderArena*);
@@ -58,6 +61,12 @@ public:
// Overridden to prevent the normal delete from being called.
void operator delete(void*, size_t);
+ void clearPaginationInformation();
+ bool isPaginatingColumns() const { return m_columnInfo; }
+ bool isPaginated() const { return m_pageHeight || m_columnInfo; }
+ int pageY(int childY) const;
+ void addForcedColumnBreak(int childY);
+
private:
// The normal operator new is disallowed.
void* operator new(size_t) throw();
@@ -65,10 +74,16 @@ private:
public:
bool m_clipped;
IntRect m_clipRect;
- IntSize m_offset; // x/y offset from container.
- IntSize m_layoutDelta; // Transient offset from the final position of the object
- // used to ensure that repaints happen in the correct place.
- // This is a total delta accumulated from the root.
+ IntSize m_paintOffset; // x/y offset from container. Includes relative positioning and scroll offsets.
+ IntSize m_layoutOffset; // x/y offset from container. Does not include relative positioning or scroll offsets.
+ IntSize m_layoutDelta; // Transient offset from the final position of the object
+ // used to ensure that repaints happen in the correct place.
+ // This is a total delta accumulated from the root.
+
+ int m_pageHeight; // The current page height for the pagination model that encloses us.
+ IntSize m_pageOffset; // The offset of the start of the first page in the nearest enclosing pagination model.
+ ColumnInfo* m_columnInfo; // If the enclosing pagination model is a column model, then this will store column information for easy retrieval/manipulation.
+
LayoutState* m_next;
#ifndef NDEBUG
RenderObject* m_renderer;
diff --git a/WebCore/rendering/MediaControlElements.cpp b/WebCore/rendering/MediaControlElements.cpp
index aaeb3e2..5533326 100644
--- a/WebCore/rendering/MediaControlElements.cpp
+++ b/WebCore/rendering/MediaControlElements.cpp
@@ -350,7 +350,7 @@ MediaControlInputElement::MediaControlInputElement(HTMLMediaElement* mediaElemen
, m_mediaElement(mediaElement)
, m_pseudoStyleId(pseudo)
{
- setInputType(type);
+ setType(type);
setInDocument();
switch (pseudo) {
diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp
index 52f5c52..0e44b32 100644
--- a/WebCore/rendering/RenderBlock.cpp
+++ b/WebCore/rendering/RenderBlock.cpp
@@ -118,7 +118,7 @@ RenderBlock::RenderBlock(Node* node)
, m_floatingObjects(0)
, m_positionedObjects(0)
, m_continuation(0)
- , m_maxMargin(0)
+ , m_rareData(0)
, m_lineHeight(-1)
{
setChildrenInline(true);
@@ -128,7 +128,6 @@ RenderBlock::~RenderBlock()
{
delete m_floatingObjects;
delete m_positionedObjects;
- delete m_maxMargin;
if (hasColumns())
delete gColumnInfoMap->take(this);
@@ -1116,7 +1115,7 @@ void RenderBlock::layout()
clearLayoutOverflow();
}
-void RenderBlock::layoutBlock(bool relayoutChildren)
+void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight)
{
ASSERT(needsLayout());
@@ -1127,7 +1126,6 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
return;
LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout());
- LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection());
int oldWidth = width();
int oldColumnWidth = desiredColumnWidth();
@@ -1148,6 +1146,30 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
int previousHeight = height();
setHeight(0);
+ bool hasSpecifiedPageHeight = false;
+ ColumnInfo* colInfo = columnInfo();
+ if (hasColumns()) {
+ if (!pageHeight) {
+ // We need to go ahead and set our explicit page height if one exists, so that we can
+ // avoid doing two layout passes.
+ calcHeight();
+ int columnHeight = contentHeight();
+ if (columnHeight > 0) {
+ pageHeight = columnHeight;
+ hasSpecifiedPageHeight = true;
+ }
+ setHeight(0);
+ }
+ if (colInfo->columnHeight() != pageHeight && m_everHadLayout) {
+ colInfo->setColumnHeight(pageHeight);
+ markDescendantBlocksAndLinesForLayout(); // We need to dirty all descendant blocks and lines, since the column height is different now.
+ }
+
+ if (!hasSpecifiedPageHeight && !pageHeight)
+ colInfo->clearForcedBreaks();
+ }
+
+ LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection(), pageHeight, colInfo);
// We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
// our current maximal positive and negative margins. These values are used when we
@@ -1162,7 +1184,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
bool isCell = isTableCell();
if (!isCell) {
initMaxMarginValues();
-
+
setTopMarginQuirk(style()->marginTop().quirk());
setBottomMarginQuirk(style()->marginBottom().quirk());
@@ -1172,6 +1194,8 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
// a bottom margin.
setMaxBottomMargins(0, 0);
}
+
+ setPaginationStrut(0);
}
// For overflow:scroll blocks, ensure we have both scrollbars in place always.
@@ -1197,10 +1221,9 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
if (floatBottom() > (height() - toAdd) && expandsToEncloseOverhangingFloats())
setHeight(floatBottom() + toAdd);
- // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as
- // we adjust for clean column breaks.
- int singleColumnBottom = layoutColumns();
-
+ if (layoutColumns(hasSpecifiedPageHeight, pageHeight, statePusher))
+ return;
+
// Calculate our new height.
int oldHeight = height();
calcHeight();
@@ -1215,21 +1238,18 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
}
}
}
-
- // We have to rebalance columns to the new height.
- layoutColumns(singleColumnBottom);
}
if (previousHeight != height())
relayoutChildren = true;
- // This check is designed to catch anyone
- // who wasn't going to propagate float information up to the parent and yet could potentially be painted by its ancestor.
- if (isRoot() || expandsToEncloseOverhangingFloats())
- addOverflowFromFloats();
-
// Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
if (!hasColumns()) {
+ // This check is designed to catch anyone
+ // who wasn't going to propagate float information up to the parent and yet could potentially be painted by its ancestor.
+ if (isRoot() || expandsToEncloseOverhangingFloats())
+ addOverflowFromFloats();
+
if (childrenInline())
addOverflowFromInlineChildren();
else
@@ -1245,6 +1265,9 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
statePusher.pop();
+ if (view()->layoutState()->m_pageHeight)
+ setPageY(view()->layoutState()->pageY(y()));
+
// Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
// we overflow or not.
updateScrollInfoAfterLayout();
@@ -1493,7 +1516,8 @@ int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop))
marginInfo.setTopQuirk(topQuirk);
- int ypos = height();
+ int beforeCollapseY = height();
+ int ypos = beforeCollapseY;
if (child->isSelfCollapsingBlock()) {
// This child has no height. We need to compute our
// position before we collapse the child's margins together,
@@ -1535,6 +1559,14 @@ int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
marginInfo.setBottomQuirk(child->isBottomMarginQuirk() || style()->marginBottomCollapse() == MDISCARD);
}
+ // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
+ // collapsed into the page edge.
+ bool paginated = view()->layoutState()->isPaginated();
+ if (paginated && ypos > beforeCollapseY) {
+ int oldY = ypos;
+ ypos = min(ypos, nextPageTop(beforeCollapseY));
+ setHeight(height() + (ypos - oldY));
+ }
return ypos;
}
@@ -1594,7 +1626,27 @@ int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& ma
int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop();
yPosEstimate += max(marginInfo.margin(), childMarginTop);
}
+
+ bool paginated = view()->layoutState()->isPaginated();
+
+ // Adjust yPosEstimate down to the next page if the margins are so large that we don't fit on the current
+ // page.
+ if (paginated && yPosEstimate > height())
+ yPosEstimate = min(yPosEstimate, nextPageTop(height()));
+
yPosEstimate += getClearDelta(child, yPosEstimate);
+
+ if (paginated) {
+ // If the object has a page or column break value of "before", then we should shift to the top of the next page.
+ yPosEstimate = applyBeforeBreak(child, yPosEstimate);
+
+ // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
+ yPosEstimate = adjustForUnsplittableChild(child, yPosEstimate);
+
+ if (!child->selfNeedsLayout() && child->isRenderBlock())
+ yPosEstimate += toRenderBlock(child)->paginationStrut();
+ }
+
return yPosEstimate;
}
@@ -1784,8 +1836,9 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int
view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate));
child->setLocation(child->x(), yPosEstimate);
+ RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
bool markDescendantsWithFloats = false;
- if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats())
+ if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
markDescendantsWithFloats = true;
else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
// If an element might be affected by the presence of floats, then always mark it for
@@ -1795,18 +1848,24 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int
markDescendantsWithFloats = true;
}
- if (child->isRenderBlock()) {
+ if (childRenderBlock) {
if (markDescendantsWithFloats)
- toRenderBlock(child)->markAllDescendantsWithFloatsForLayout();
-
+ childRenderBlock->markAllDescendantsWithFloatsForLayout();
previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom());
}
+ bool paginated = view()->layoutState()->isPaginated();
+ if (!child->needsLayout() && paginated && view()->layoutState()->m_pageHeight && childRenderBlock && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY())
+ childRenderBlock->markForPaginationRelayout();
+
bool childHadLayout = child->m_everHadLayout;
bool childNeededLayout = child->needsLayout();
if (childNeededLayout)
child->layout();
+ // Cache if we are at the top of the block right now.
+ bool atTopOfBlock = marginInfo.atTopOfBlock();
+
// Now determine the correct ypos based off examination of collapsing margin
// values.
int yBeforeClear = collapseMargins(child, marginInfo);
@@ -1814,6 +1873,41 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int
// Now check for clear.
int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear);
+ if (paginated) {
+ int oldY = yAfterClear;
+
+ // If the object has a page or column break value of "before", then we should shift to the top of the next page.
+ yAfterClear = applyBeforeBreak(child, yAfterClear);
+
+ // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
+ int yBeforeUnsplittableAdjustment = yAfterClear;
+ int yAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, yAfterClear);
+
+ int paginationStrut = 0;
+ int unsplittableAdjustmentDelta = yAfterUnsplittableAdjustment - yBeforeUnsplittableAdjustment;
+ if (unsplittableAdjustmentDelta)
+ paginationStrut = unsplittableAdjustmentDelta;
+ else if (childRenderBlock && childRenderBlock->paginationStrut())
+ paginationStrut = childRenderBlock->paginationStrut();
+
+ if (paginationStrut) {
+ // We are willing to propagate out to our parent block as long as we were at the top of the block prior
+ // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
+ if (atTopOfBlock && oldY == yBeforeClear && !isPositioned() && !isTableCell()) {
+ // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
+ // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
+ // and pushes to the next page anyway, so not too concerned about it.
+ setPaginationStrut(yAfterClear + paginationStrut);
+ if (childRenderBlock)
+ childRenderBlock->setPaginationStrut(0);
+ } else
+ yAfterClear += paginationStrut;
+ }
+
+ // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
+ setHeight(height() + (yAfterClear - oldY));
+ }
+
view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear));
child->setLocation(child->x(), yAfterClear);
@@ -1826,8 +1920,13 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int
// So go ahead and mark the item as dirty.
child->setChildNeedsLayout(true, false);
}
- if (!child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats())
- toRenderBlock(child)->markAllDescendantsWithFloatsForLayout();
+ if (childRenderBlock) {
+ if (!child->avoidsFloats() && childRenderBlock->containsFloats())
+ childRenderBlock->markAllDescendantsWithFloatsForLayout();
+ if (paginated && !child->needsLayout() && view()->layoutState()->m_pageHeight && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY())
+ childRenderBlock->markForPaginationRelayout();
+ }
+
// Our guess was wrong. Make the child lay itself out again.
child->layoutIfNeeded();
}
@@ -1848,7 +1947,7 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int
}
// If the child has overhanging floats that intrude into following siblings (or possibly out
// of this block), then the parent gets notified of the floats now.
- if (child->isBlockFlow() && toRenderBlock(child)->containsFloats())
+ if (childRenderBlock && childRenderBlock->containsFloats())
maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout));
IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y());
@@ -1867,6 +1966,13 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int
child->repaintOverhangingFloats(true);
}
+ if (paginated) {
+ // Check for an after page/column break.
+ int newHeight = applyAfterBreak(child, height(), marginInfo);
+ if (newHeight != height())
+ setHeight(newHeight);
+ }
+
ASSERT(oldLayoutDelta == view()->layoutDelta());
}
@@ -1904,6 +2010,11 @@ bool RenderBlock::layoutOnlyPositionedObjects()
void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
{
if (m_positionedObjects) {
+ if (hasColumns())
+ view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
+
+ bool paginated = view()->layoutState()->isPaginated();
+
RenderBox* r;
Iterator end = m_positionedObjects->end();
for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
@@ -1919,12 +2030,21 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
//if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent()))
r->setPrefWidthsDirty(true, false);
+ if (!r->needsLayout() && paginated && view()->layoutState()->m_pageHeight) {
+ RenderBlock* childRenderBlock = r->isRenderBlock() ? toRenderBlock(r) : 0;
+ if (childRenderBlock && view()->layoutState()->pageY(childRenderBlock->y()) != childRenderBlock->pageY())
+ childRenderBlock->markForPaginationRelayout();
+ }
+
// We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width
// and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
if (r->needsPositionedMovementLayoutOnly())
r->tryLayoutDoingPositionedMovementOnly();
r->layoutIfNeeded();
}
+
+ if (hasColumns())
+ view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
}
}
@@ -2012,12 +2132,12 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty)
// We need to do multiple passes, breaking up our child painting into strips.
ColumnInfo* colInfo = columnInfo();
- unsigned colCount = colInfo->columnCount();
+ unsigned colCount = columnCount(colInfo);
int currXOffset = style()->direction() == LTR ? 0 : contentWidth();
int ruleAdd = borderLeft() + paddingLeft();
int ruleX = style()->direction() == LTR ? 0 : contentWidth();
for (unsigned i = 0; i < colCount; i++) {
- IntRect colRect = colInfo->columnRectAt(i);
+ IntRect colRect = columnRectAt(colInfo, i);
// Move to the next position.
if (style()->direction() == LTR) {
@@ -2048,14 +2168,14 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool
GraphicsContext* context = paintInfo.context;
int colGap = columnGap();
ColumnInfo* colInfo = columnInfo();
- unsigned colCount = colInfo->columnCount();
+ unsigned colCount = columnCount(colInfo);
if (!colCount)
return;
- int currXOffset = style()->direction() == LTR ? 0 : contentWidth() - colInfo->columnRectAt(0).width();
+ int currXOffset = style()->direction() == LTR ? 0 : contentWidth() - columnRectAt(colInfo, 0).width();
int currYOffset = 0;
for (unsigned i = 0; i < colCount; i++) {
// For each rect, we clip to the rect, and then we adjust our coords.
- IntRect colRect = colInfo->columnRectAt(i);
+ IntRect colRect = columnRectAt(colInfo, i);
colRect.move(tx, ty);
PaintInfo info(paintInfo);
info.rect.intersect(colRect);
@@ -2112,15 +2232,14 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty)
info.phase = newPhase;
info.updatePaintingRootForChildren(this);
+ // FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
+ // NSViews. Do not add any more code for this.
RenderView* renderView = view();
- bool usePrintRect = !renderView->printRect().isEmpty() && !document()->settings()->paginateDuringLayoutEnabled();
+ bool usePrintRect = !renderView->printRect().isEmpty();
- bool checkPageBreaks = document()->paginated() && !document()->settings()->paginateDuringLayoutEnabled();
- bool checkColumnBreaks = !checkPageBreaks && usePrintRect;
-
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
// Check for page-break-before: always, and if it's set, break and bail.
- bool checkBeforeAlways = !childrenInline() && ((checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS) || (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS));
+ bool checkBeforeAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakBefore() == PBALWAYS);
if (checkBeforeAlways
&& (ty + child->y()) > paintInfo.rect.y()
&& (ty + child->y()) < paintInfo.rect.bottom()) {
@@ -2143,7 +2262,7 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty)
child->paint(info, tx, ty);
// Check for page-break-after: always, and if it's set, break and bail.
- bool checkAfterAlways = !childrenInline() && ((checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS) || (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS));
+ bool checkAfterAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakAfter() == PBALWAYS);
if (checkAfterAlways
&& (ty + child->y() + child->height()) > paintInfo.rect.y()
&& (ty + child->y() + child->height()) < paintInfo.rect.bottom()) {
@@ -2155,7 +2274,7 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty)
void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType type)
{
- SelectionController* selection = type == CursorCaret ? frame()->selection() : frame()->dragCaretController();
+ SelectionController* selection = type == CursorCaret ? frame()->selection() : frame()->page()->dragCaretController();
// Paint the caret if the SelectionController says so or if caret browsing is enabled
bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled();
@@ -2168,7 +2287,7 @@ void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType typ
if (type == CursorCaret)
frame()->selection()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect);
else
- frame()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect);
+ frame()->selection()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect);
}
}
@@ -2791,7 +2910,7 @@ void RenderBlock::removePositionedObjects(RenderBlock* o)
m_positionedObjects->remove(deadObjects.at(i));
}
-void RenderBlock::insertFloatingObject(RenderBox* o)
+RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
{
ASSERT(o->isFloating());
@@ -2804,25 +2923,37 @@ void RenderBlock::insertFloatingObject(RenderBox* o)
DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
FloatingObject* f;
while ( (f = it.current()) ) {
- if (f->m_renderer == o) return;
+ if (f->m_renderer == o)
+ return f;
++it;
}
}
// Create the special object entry & append it to the list
- o->layoutIfNeeded();
-
FloatingObject* newObj = new FloatingObject(o->style()->floating() == FLEFT ? FloatingObject::FloatLeft : FloatingObject::FloatRight);
newObj->m_top = -1;
newObj->m_bottom = -1;
+
+ // Our location is irrelevant if we're unsplittable or no pagination is in effect.
+ // Just go ahead and lay out the float.
+ bool affectedByPagination = o->isRenderBlock() && view()->layoutState()->m_pageHeight;
+ if (!affectedByPagination)
+ o->layoutIfNeeded();
+ else {
+ o->calcWidth();
+ o->calcVerticalMargins();
+ }
newObj->m_width = o->width() + o->marginLeft() + o->marginRight();
+
newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will.
newObj->m_isDescendant = true;
newObj->m_renderer = o;
m_floatingObjects->append(newObj);
+
+ return newObj;
}
void RenderBlock::removeFloatingObject(RenderBox* o)
@@ -2846,6 +2977,18 @@ void RenderBlock::removeFloatingObject(RenderBox* o)
}
}
+void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int y)
+{
+ if (!m_floatingObjects)
+ return;
+
+ FloatingObject* curr = m_floatingObjects->last();
+ while (curr != lastFloat && (curr->m_top == -1 || curr->m_top >= y)) {
+ m_floatingObjects->removeLast();
+ curr = m_floatingObjects->last();
+ }
+}
+
bool RenderBlock::positionNewFloats()
{
if (!m_floatingObjects)
@@ -2882,16 +3025,15 @@ bool RenderBlock::positionNewFloats()
}
RenderBox* o = f->m_renderer;
- int _height = o->height() + o->marginTop() + o->marginBottom();
int ro = rightOffset(); // Constant part of right offset.
- int lo = leftOffset(); // Constat part of left offset.
+ int lo = leftOffset(); // Constant part of left offset.
int fwidth = f->m_width; // The width we look for.
if (ro - lo < fwidth)
fwidth = ro - lo; // Never look for more than what will be available.
IntRect oldRect(o->x(), o->y() , o->width(), o->height());
-
+
if (o->style()->clear() & CLEFT)
y = max(leftBottom(), y);
if (o->style()->clear() & CRIGHT)
@@ -2920,9 +3062,38 @@ bool RenderBlock::positionNewFloats()
o->setLocation(fx - o->marginRight() - o->width(), y + o->marginTop());
}
- f->m_top = y;
- f->m_bottom = f->m_top + _height;
+ if (view()->layoutState()->isPaginated()) {
+ RenderBlock* childBlock = o->isRenderBlock() ? toRenderBlock(o) : 0;
+ if (childBlock && view()->layoutState()->m_pageHeight && view()->layoutState()->pageY(o->y()) != childBlock->pageY())
+ childBlock->markForPaginationRelayout();
+ o->layoutIfNeeded();
+
+ // If we are unsplittable and don't fit, then we need to move down.
+ // We include our margins as part of the unsplittable area.
+ int newY = adjustForUnsplittableChild(o, y, true);
+
+ // See if we have a pagination strut that is making us move down further.
+ // Note that an unsplittable child can't also have a pagination strut, so this is
+ // exclusive with the case above.
+ if (childBlock && childBlock->paginationStrut()) {
+ newY += childBlock->paginationStrut();
+ childBlock->setPaginationStrut(0);
+ }
+
+ if (newY != y) {
+ f->m_paginationStrut = newY - y;
+ y = newY;
+ o->setY(y + o->marginTop());
+ if (childBlock)
+ childBlock->setChildNeedsLayout(true, false);
+ o->layoutIfNeeded();
+ }
+ }
+
+ f->m_top = y;
+ f->m_bottom = f->m_top + o->marginTop() + o->height() + o->marginBottom();
+
// If the child moved, we have to repaint it.
if (o->checkForRepaintDuringLayout())
o->repaintDuringLayoutIfMoved(oldRect);
@@ -2932,6 +3103,40 @@ bool RenderBlock::positionNewFloats()
return true;
}
+bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine)
+{
+ bool didPosition = positionNewFloats();
+ if (!didPosition || !newFloat->m_paginationStrut)
+ return didPosition;
+
+ int floatTop = newFloat->m_top;
+ int paginationStrut = newFloat->m_paginationStrut;
+ FloatingObject* f = m_floatingObjects->last();
+
+ ASSERT(f == newFloat);
+
+ if (floatTop - paginationStrut != height())
+ return didPosition;
+
+ for (f = m_floatingObjects->prev(); f && f != lastFloatFromPreviousLine; f = m_floatingObjects->prev()) {
+ if (f->m_top == height()) {
+ ASSERT(!f->m_paginationStrut);
+ f->m_paginationStrut = paginationStrut;
+ RenderBox* o = f->m_renderer;
+ o->setY(o->y() + o->marginTop() + paginationStrut);
+ if (o->isRenderBlock())
+ toRenderBlock(o)->setChildNeedsLayout(true, false);
+ o->layoutIfNeeded();
+ f->m_top += f->m_paginationStrut;
+ f->m_bottom += f->m_paginationStrut;
+ }
+ }
+
+ setHeight(height() + paginationStrut);
+
+ return didPosition;
+}
+
void RenderBlock::newLine(EClear clear)
{
positionNewFloats();
@@ -3173,8 +3378,8 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
if (hasColumns()) {
ColumnInfo* colInfo = columnInfo();
- for (unsigned i = 0; i < colInfo->columnCount(); i++)
- bottom = max(bottom, colInfo->columnRectAt(i).bottom() + relativeOffset);
+ for (unsigned i = 0; i < columnCount(colInfo); i++)
+ bottom = max(bottom, columnRectAt(colInfo, i).bottom() + relativeOffset);
return bottom;
}
@@ -3268,8 +3473,9 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
// This only matters for LTR
if (style()->direction() == LTR) {
ColumnInfo* colInfo = columnInfo();
- if (colInfo->columnCount())
- right = max(colInfo->columnRectAt(colInfo->columnCount() - 1).right() + relativeOffset, right);
+ unsigned count = columnCount(colInfo);
+ if (count)
+ right = max(columnRectAt(colInfo, count - 1).right() + relativeOffset, right);
}
return right;
}
@@ -3368,8 +3574,9 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
// This only matters for RTL
if (style()->direction() == RTL) {
ColumnInfo* colInfo = columnInfo();
- if (colInfo->columnCount())
- left = min(colInfo->columnRectAt(colInfo->columnCount() - 1).x() + relativeOffset, left);
+ unsigned count = columnCount(colInfo);
+ if (count)
+ left = min(columnRectAt(colInfo, count - 1).x() + relativeOffset, left);
}
return left;
}
@@ -3662,6 +3869,9 @@ bool RenderBlock::containsFloat(RenderObject* o)
void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
{
+ if (!m_everHadLayout)
+ return;
+
setChildNeedsLayout(true, !inLayout);
if (floatToRemove)
@@ -3679,30 +3889,39 @@ void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove
}
}
-int RenderBlock::visibleTopOfHighestFloatExtendingBelow(int bottom, int maxHeight) const
+void RenderBlock::markDescendantBlocksAndLinesForLayout(bool inLayout)
{
- int top = bottom;
- if (m_floatingObjects) {
- FloatingObject* floatingObject;
- for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); (floatingObject = it.current()); ++it) {
- RenderBox* floatingBox = floatingObject->m_renderer;
- IntRect visibleOverflow = floatingBox->visibleOverflowRect();
- visibleOverflow.move(floatingBox->x(), floatingBox->y());
- if (visibleOverflow.y() < top && visibleOverflow.bottom() > bottom && visibleOverflow.height() <= maxHeight && floatingBox->containingBlock() == this)
- top = visibleOverflow.y();
- }
- }
+ if (!m_everHadLayout)
+ return;
+
+ setChildNeedsLayout(true, !inLayout);
+ // Iterate over our children and mark them as needed.
if (!childrenInline()) {
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (child->isFloatingOrPositioned() || !child->isRenderBlock())
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ if (child->isFloatingOrPositioned())
continue;
- RenderBlock* childBlock = toRenderBlock(child);
- top = min(top, childBlock->y() + childBlock->visibleTopOfHighestFloatExtendingBelow(bottom - childBlock->y(), maxHeight));
+ child->markDescendantBlocksAndLinesForLayout(inLayout);
+ }
+ }
+
+ // Walk our floating objects and mark them too.
+ if (m_floatingObjects) {
+ DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ while (it.current()) {
+ if (it.current()->m_renderer->isRenderBlock())
+ it.current()->m_renderer->markDescendantBlocksAndLinesForLayout(inLayout);
+ ++it;
}
}
- return top;
+ if (m_positionedObjects) {
+ // FIXME: Technically we don't have to mark the positioned objects if we're the block
+ // that established the columns, but we don't really have that information here.
+ Iterator end = m_positionedObjects->end();
+ for (Iterator it = m_positionedObjects->begin(); it != end; ++it)
+ (*it)->markDescendantBlocksAndLinesForLayout();
+ }
}
int RenderBlock::getClearDelta(RenderBox* child, int yPos)
@@ -3862,16 +4081,16 @@ bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& r
{
// We need to do multiple passes, breaking up our hit testing into strips.
ColumnInfo* colInfo = columnInfo();
- int colCount = colInfo->columnCount();
+ int colCount = columnCount(colInfo);
if (!colCount)
return false;
int left = borderLeft() + paddingLeft();
int currYOffset = 0;
int i;
for (i = 0; i < colCount; i++)
- currYOffset -= colInfo->columnRectAt(i).height();
+ currYOffset -= columnRectAt(colInfo, i).height();
for (i = colCount - 1; i >= 0; i--) {
- IntRect colRect = colInfo->columnRectAt(i);
+ IntRect colRect = columnRectAt(colInfo, i);
int currXOffset = colRect.x() - left;
currYOffset += colRect.height();
colRect.move(tx, ty);
@@ -4101,7 +4320,15 @@ int RenderBlock::availableWidth() const
// If we have multiple columns, then the available width is reduced to our column width.
if (hasColumns())
return desiredColumnWidth();
- return contentWidth();
+ return RenderBox::availableWidth();
+}
+
+int RenderBlock::availableLogicalWidth() const
+{
+ // If we have multiple columns, then the available logical width is reduced to our column width.
+ if (hasColumns())
+ return desiredColumnWidth();
+ return RenderBox::availableLogicalWidth();
}
int RenderBlock::columnGap() const
@@ -4165,8 +4392,7 @@ void RenderBlock::setDesiredColumnCountAndWidth(int count, int width)
bool destroyColumns = !firstChild()
|| (count == 1 && style()->hasAutoColumnWidth())
|| firstChild()->isAnonymousColumnsBlock()
- || firstChild()->isAnonymousColumnSpanBlock()
- || document()->settings()->paginateDuringLayoutEnabled();
+ || firstChild()->isAnonymousColumnSpanBlock();
if (destroyColumns) {
if (hasColumns()) {
delete gColumnInfoMap->take(this);
@@ -4209,133 +4435,75 @@ ColumnInfo* RenderBlock::columnInfo() const
return gColumnInfoMap->get(this);
}
-int RenderBlock::layoutColumns(int endOfContent, int requestedColumnHeight)
+unsigned RenderBlock::columnCount(ColumnInfo* colInfo) const
{
- // Don't do anything if we have no columns
- if (!hasColumns())
- return -1;
+ ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo);
+ return colInfo->columnCount();
+}
- ColumnInfo* info = gColumnInfoMap->get(this);
- int desiredColumnWidth = info->desiredColumnWidth();
- int desiredColumnCount = info->desiredColumnCount();
-
- bool computeIntrinsicHeight = (endOfContent == -1);
-
- // Fill the columns in to the available height. Attempt to balance the height of the columns.
- // Add in half our line-height to help with best-guess initial balancing.
- int columnSlop = lineHeight(false) / 2;
- int remainingSlopSpace = columnSlop * desiredColumnCount;
- int availableHeight = contentHeight();
- int colHeight;
- if (computeIntrinsicHeight && requestedColumnHeight >= 0)
- colHeight = requestedColumnHeight;
- else if (computeIntrinsicHeight)
- colHeight = min(availableHeight, availableHeight / desiredColumnCount + columnSlop);
- else
- colHeight = availableHeight;
- int originalColHeight = colHeight;
+IntRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
+{
+ ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo);
+ // Compute the appropriate rect based off our information.
+ int colWidth = colInfo->desiredColumnWidth();
+ int colHeight = colInfo->columnHeight();
+ int colTop = borderTop() + paddingTop();
int colGap = columnGap();
+ int colLeft = style()->direction() == LTR ?
+ borderLeft() + paddingLeft() + (index * (colWidth + colGap))
+ : borderLeft() + paddingLeft() + contentWidth() - colWidth - (index * (colWidth + colGap));
+ return IntRect(colLeft, colTop, colWidth, colHeight);
+}
- // Compute a collection of column rects.
- info->clearColumns();
-
- // Then we do a simulated "paint" into the column slices and allow the content to slightly adjust our individual column rects.
- // FIXME: We need to take into account layers that are affected by the columns as well here so that they can have an opportunity
- // to adjust column rects also.
- RenderView* v = view();
- int left = borderLeft() + paddingLeft();
- int top = borderTop() + paddingTop();
- int currX = style()->direction() == LTR ? borderLeft() + paddingLeft() : borderLeft() + paddingLeft() + contentWidth() - desiredColumnWidth;
- int currY = top;
- unsigned colCount = desiredColumnCount;
- int maxColBottom = borderTop() + paddingTop();
- int contentBottom = top + availableHeight;
- int minimumColumnHeight = -1;
- for (unsigned i = 0; i < colCount; i++) {
- // If we aren't constrained, then the last column can just get all the remaining space.
- if (computeIntrinsicHeight && i == colCount - 1)
- colHeight = availableHeight;
-
- // This represents the real column position.
- IntRect colRect(currX, top, desiredColumnWidth, colHeight);
-
- int truncationPoint = visibleTopOfHighestFloatExtendingBelow(currY + colHeight, colHeight);
-
- // For the simulated paint, we pretend like everything is in one long strip.
- IntRect pageRect(left, currY, contentWidth(), truncationPoint - currY);
- v->setPrintRect(pageRect);
- v->setTruncatedAt(truncationPoint);
- GraphicsContext context((PlatformGraphicsContext*)0);
- PaintInfo paintInfo(&context, pageRect, PaintPhaseForeground, false, 0, 0);
+bool RenderBlock::layoutColumns(bool hasSpecifiedPageHeight, int pageHeight, LayoutStateMaintainer& statePusher)
+{
+ if (hasColumns()) {
+ // FIXME: We don't balance properly at all in the presence of forced page breaks. We need to understand what
+ // the distance between forced page breaks is so that we can avoid making the minimum column height too tall.
+ ColumnInfo* colInfo = columnInfo();
+ int desiredColumnCount = colInfo->desiredColumnCount();
+ if (!hasSpecifiedPageHeight) {
+ int columnHeight = pageHeight;
+ int minColumnCount = colInfo->forcedBreaks() + 1;
+ if (minColumnCount >= desiredColumnCount) {
+ // The forced page breaks are in control of the balancing. Just set the column height to the
+ // maximum page break distance.
+ if (!pageHeight) {
+ int distanceBetweenBreaks = max(colInfo->maximumDistanceBetweenForcedBreaks(),
+ view()->layoutState()->pageY(borderTop() + paddingTop() + contentHeight()) - colInfo->forcedBreakOffset());
+ columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks);
+ }
+ } else if (contentHeight() > pageHeight * desiredColumnCount) {
+ // Now that we know the intrinsic height of the columns, we have to rebalance them.
+ columnHeight = max(colInfo->minimumColumnHeight(), (int)ceilf((float)contentHeight() / desiredColumnCount));
+ }
+
+ if (columnHeight && columnHeight != pageHeight) {
+ statePusher.pop();
+ m_everHadLayout = true;
+ layoutBlock(false, columnHeight);
+ return true;
+ }
+ }
- setHasColumns(false);
- paintObject(paintInfo, 0, 0);
- setHasColumns(true);
-
- if (computeIntrinsicHeight && v->minimumColumnHeight() > originalColHeight) {
- // The initial column height was too small to contain one line of text.
- minimumColumnHeight = max(minimumColumnHeight, v->minimumColumnHeight());
- }
+ if (pageHeight) // FIXME: Should we use lowestPosition (excluding our positioned objects) instead of contentHeight()?
+ colInfo->setColumnCountAndHeight(ceilf((float)contentHeight() / pageHeight), pageHeight);
+
+ if (columnCount(colInfo)) {
+ IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
+ int overflowLeft = style()->direction() == RTL ? min(0, lastRect.x()) : 0;
+ int overflowRight = style()->direction() == LTR ? max(width(), lastRect.x() + lastRect.width()) : 0;
+ int overflowHeight = borderTop() + paddingTop() + colInfo->columnHeight();
+
+ setHeight(overflowHeight + borderBottom() + paddingBottom() + horizontalScrollbarHeight());
- int adjustedBottom = v->bestTruncatedAt();
- if (adjustedBottom <= currY)
- adjustedBottom = truncationPoint;
-
- colRect.setHeight(adjustedBottom - currY);
-
- // Add in the lost space to the subsequent columns.
- // FIXME: This will create a "staircase" effect if there are enough columns, but the effect should be pretty subtle.
- if (computeIntrinsicHeight) {
- int lostSpace = colHeight - colRect.height();
- if (lostSpace > remainingSlopSpace) {
- // Redestribute the space among the remaining columns.
- int spaceToRedistribute = lostSpace - remainingSlopSpace;
- int remainingColumns = colCount - i + 1;
- colHeight += spaceToRedistribute / remainingColumns;
- }
- remainingSlopSpace = max(0, remainingSlopSpace - lostSpace);
+ m_overflow.clear();
+ addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
}
-
- if (style()->direction() == LTR)
- currX += desiredColumnWidth + colGap;
- else
- currX -= (desiredColumnWidth + colGap);
-
- currY += colRect.height();
- availableHeight -= colRect.height();
-
- maxColBottom = max(colRect.bottom(), maxColBottom);
-
- info->addColumnRect(colRect);
-
- // Start adding in more columns as long as there's still content left.
- if (currY < endOfContent && i == colCount - 1 && (computeIntrinsicHeight || contentHeight()))
- colCount++;
- }
-
- if (minimumColumnHeight >= 0) {
- // If originalColHeight was too small, we need to try to layout again.
- return layoutColumns(endOfContent, minimumColumnHeight);
}
-
- int overflowRight = max(width(), currX - colGap);
- int overflowLeft = min(0, currX + desiredColumnWidth + colGap);
- int overflowHeight = maxColBottom;
- int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
-
- if (computeIntrinsicHeight)
- setHeight(maxColBottom + toAdd);
-
- m_overflow.clear();
- addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
-
- v->setPrintRect(IntRect());
- v->setTruncatedAt(0);
- ASSERT(colCount == info->columnCount());
-
- return contentBottom;
+ return false;
}
void RenderBlock::adjustPointToColumnContents(IntPoint& point) const
@@ -4345,17 +4513,17 @@ void RenderBlock::adjustPointToColumnContents(IntPoint& point) const
return;
ColumnInfo* colInfo = columnInfo();
- if (!colInfo->columnCount())
+ if (!columnCount(colInfo))
return;
// Determine which columns we intersect.
int colGap = columnGap();
int leftGap = colGap / 2;
- IntPoint columnPoint(colInfo->columnRectAt(0).location());
+ IntPoint columnPoint(columnRectAt(colInfo, 0).location());
int yOffset = 0;
for (unsigned i = 0; i < colInfo->columnCount(); i++) {
// Add in half the column gap to the left and right of the rect.
- IntRect colRect = colInfo->columnRectAt(i);
+ IntRect colRect = columnRectAt(colInfo, i);
IntRect gapAndColumnRect(colRect.x() - leftGap, colRect.y(), colRect.width() + colGap, colRect.height());
if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.right()) {
@@ -4393,7 +4561,7 @@ void RenderBlock::adjustRectForColumns(IntRect& r) const
IntRect result;
// Determine which columns we intersect.
- unsigned colCount = colInfo->columnCount();
+ unsigned colCount = columnCount(colInfo);
if (!colCount)
return;
@@ -4401,7 +4569,7 @@ void RenderBlock::adjustRectForColumns(IntRect& r) const
int currYOffset = 0;
for (unsigned i = 0; i < colCount; i++) {
- IntRect colRect = colInfo->columnRectAt(i);
+ IntRect colRect = columnRectAt(colInfo, i);
int currXOffset = colRect.x() - left;
IntRect repaintRect = r;
@@ -4427,9 +4595,9 @@ void RenderBlock::adjustForColumns(IntSize& offset, const IntPoint& point) const
int left = borderLeft() + paddingLeft();
int yOffset = 0;
- size_t columnCount = colInfo->columnCount();
- for (size_t i = 0; i < columnCount; ++i) {
- IntRect columnRect = colInfo->columnRectAt(i);
+ size_t colCount = columnCount(colInfo);
+ for (size_t i = 0; i < colCount; ++i) {
+ IntRect columnRect = columnRectAt(colInfo, i);
int xOffset = columnRect.x() - left;
if (point.y() < columnRect.bottom() + yOffset) {
offset.expand(xOffset, -yOffset);
@@ -5108,6 +5276,16 @@ RenderBlock* RenderBlock::firstLineBlock() const
return firstLineBlock;
}
+static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer)
+{
+ RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle());
+ // Force inline display (except for floating first-letters).
+ pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
+ // CSS2 says first-letter can't be positioned.
+ pseudoStyle->setPosition(StaticPosition);
+ return pseudoStyle;
+}
+
void RenderBlock::updateFirstLetter()
{
if (!document()->usesFirstLetterRules())
@@ -5157,84 +5335,110 @@ void RenderBlock::updateFirstLetter()
if (!currChild)
return;
- RenderObject* firstLetterContainer = currChild->parent();
-
// If the child already has style, then it has already been created, so we just want
// to update it.
- if (firstLetterContainer->style()->styleType() == FIRST_LETTER) {
- RenderStyle* pseudo = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER,
- firstLetterContainer->parent()->firstLineStyle());
- firstLetterContainer->setStyle(pseudo);
- for (RenderObject* genChild = firstLetterContainer->firstChild(); genChild; genChild = genChild->nextSibling()) {
+ if (currChild->parent()->style()->styleType() == FIRST_LETTER) {
+ RenderObject* firstLetter = currChild->parent();
+ RenderObject* firstLetterContainer = firstLetter->parent();
+ RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
+
+ if (Node::diff(firstLetter->style(), pseudoStyle) == Node::Detach) {
+ // The first-letter renderer needs to be replaced. Create a new renderer of the right type.
+ RenderObject* newFirstLetter;
+ if (pseudoStyle->display() == INLINE)
+ newFirstLetter = new (renderArena()) RenderInline(document());
+ else
+ newFirstLetter = new (renderArena()) RenderBlock(document());
+ newFirstLetter->setStyle(pseudoStyle);
+
+ // Move the first letter into the new renderer.
+ view()->disableLayoutState();
+ while (RenderObject* child = firstLetter->firstChild()) {
+ if (child->isText())
+ toRenderText(child)->dirtyLineBoxes(true);
+ firstLetter->removeChild(child);
+ newFirstLetter->addChild(child, 0);
+ }
+ RenderTextFragment* remainingText = toRenderTextFragment(firstLetter->nextSibling());
+ ASSERT(remainingText->node()->renderer() == remainingText);
+ // Replace the old renderer with the new one.
+ remainingText->setFirstLetter(newFirstLetter);
+ firstLetter->destroy();
+ firstLetter = newFirstLetter;
+ firstLetterContainer->addChild(firstLetter, remainingText);
+ view()->enableLayoutState();
+ } else
+ firstLetter->setStyle(pseudoStyle);
+
+ for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) {
if (genChild->isText())
- genChild->setStyle(pseudo);
+ genChild->setStyle(pseudoStyle);
}
+
return;
}
+ if (!currChild->isText() || currChild->isBR())
+ return;
+
// If the child does not already have style, we create it here.
- if (currChild->isText() && !currChild->isBR() && currChild->parent()->style()->styleType() != FIRST_LETTER) {
- // Our layout state is not valid for the repaints we are going to trigger by
- // adding and removing children of firstLetterContainer.
- view()->disableLayoutState();
+ RenderObject* firstLetterContainer = currChild->parent();
- RenderText* textObj = toRenderText(currChild);
-
- // Create our pseudo style now that we have our firstLetterContainer determined.
- RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER,
- firstLetterContainer->firstLineStyle());
-
- // Force inline display (except for floating first-letters)
- pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
- pseudoStyle->setPosition(StaticPosition); // CSS2 says first-letter can't be positioned.
-
- RenderObject* firstLetter = 0;
- if (pseudoStyle->display() == INLINE)
- firstLetter = new (renderArena()) RenderInline(document());
- else
- firstLetter = new (renderArena()) RenderBlock(document());
- firstLetter->setStyle(pseudoStyle);
- firstLetterContainer->addChild(firstLetter, currChild);
-
- // The original string is going to be either a generated content string or a DOM node's
- // string. We want the original string before it got transformed in case first-letter has
- // no text-transform or a different text-transform applied to it.
- RefPtr<StringImpl> oldText = textObj->originalText();
- ASSERT(oldText);
-
- if (oldText && oldText->length() > 0) {
- unsigned int length = 0;
-
- // account for leading spaces and punctuation
- while (length < oldText->length() && (isSpaceOrNewline((*oldText)[length]) || Unicode::isPunct((*oldText)[length])))
- length++;
-
- // account for first letter
+ // Our layout state is not valid for the repaints we are going to trigger by
+ // adding and removing children of firstLetterContainer.
+ view()->disableLayoutState();
+
+ RenderText* textObj = toRenderText(currChild);
+
+ // Create our pseudo style now that we have our firstLetterContainer determined.
+ RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
+
+ RenderObject* firstLetter = 0;
+ if (pseudoStyle->display() == INLINE)
+ firstLetter = new (renderArena()) RenderInline(document());
+ else
+ firstLetter = new (renderArena()) RenderBlock(document());
+ firstLetter->setStyle(pseudoStyle);
+ firstLetterContainer->addChild(firstLetter, currChild);
+
+ // The original string is going to be either a generated content string or a DOM node's
+ // string. We want the original string before it got transformed in case first-letter has
+ // no text-transform or a different text-transform applied to it.
+ RefPtr<StringImpl> oldText = textObj->originalText();
+ ASSERT(oldText);
+
+ if (oldText && oldText->length() > 0) {
+ unsigned length = 0;
+
+ // account for leading spaces and punctuation
+ while (length < oldText->length() && (isSpaceOrNewline((*oldText)[length]) || Unicode::isPunct((*oldText)[length])))
length++;
-
- // construct text fragment for the text after the first letter
- // NOTE: this might empty
- RenderTextFragment* remainingText =
- new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length);
- remainingText->setStyle(textObj->style());
- if (remainingText->node())
- remainingText->node()->setRenderer(remainingText);
-
- RenderObject* nextObj = textObj->nextSibling();
- firstLetterContainer->removeChild(textObj);
- firstLetterContainer->addChild(remainingText, nextObj);
- remainingText->setFirstLetter(firstLetter);
-
- // construct text fragment for the first letter
- RenderTextFragment* letter =
- new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length);
- letter->setStyle(pseudoStyle);
- firstLetter->addChild(letter);
- textObj->destroy();
- }
- view()->enableLayoutState();
+ // account for first letter
+ length++;
+
+ // construct text fragment for the text after the first letter
+ // NOTE: this might empty
+ RenderTextFragment* remainingText =
+ new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length);
+ remainingText->setStyle(textObj->style());
+ if (remainingText->node())
+ remainingText->node()->setRenderer(remainingText);
+
+ RenderObject* nextObj = textObj->nextSibling();
+ firstLetterContainer->removeChild(textObj);
+ firstLetterContainer->addChild(remainingText, nextObj);
+ remainingText->setFirstLetter(firstLetter);
+
+ // construct text fragment for the first letter
+ RenderTextFragment* letter =
+ new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length);
+ letter->setStyle(pseudoStyle);
+ firstLetter->addChild(letter);
+
+ textObj->destroy();
}
+ view()->enableLayoutState();
}
// Helper methods for obtaining the last line, computing line counts and heights for line counts
@@ -5407,24 +5611,44 @@ void RenderBlock::clearTruncation()
void RenderBlock::setMaxTopMargins(int pos, int neg)
{
- if (!m_maxMargin) {
- if (pos == MaxMargin::topPosDefault(this) && neg == MaxMargin::topNegDefault(this))
+ if (!m_rareData) {
+ if (pos == RenderBlockRareData::topPosDefault(this) && neg == RenderBlockRareData::topNegDefault(this))
return;
- m_maxMargin = new MaxMargin(this);
+ m_rareData = new RenderBlockRareData(this);
}
- m_maxMargin->m_topPos = pos;
- m_maxMargin->m_topNeg = neg;
+ m_rareData->m_topPos = pos;
+ m_rareData->m_topNeg = neg;
}
void RenderBlock::setMaxBottomMargins(int pos, int neg)
{
- if (!m_maxMargin) {
- if (pos == MaxMargin::bottomPosDefault(this) && neg == MaxMargin::bottomNegDefault(this))
+ if (!m_rareData) {
+ if (pos == RenderBlockRareData::bottomPosDefault(this) && neg == RenderBlockRareData::bottomNegDefault(this))
+ return;
+ m_rareData = new RenderBlockRareData(this);
+ }
+ m_rareData->m_bottomPos = pos;
+ m_rareData->m_bottomNeg = neg;
+}
+
+void RenderBlock::setPaginationStrut(int strut)
+{
+ if (!m_rareData) {
+ if (!strut)
return;
- m_maxMargin = new MaxMargin(this);
+ m_rareData = new RenderBlockRareData(this);
}
- m_maxMargin->m_bottomPos = pos;
- m_maxMargin->m_bottomNeg = neg;
+ m_rareData->m_paginationStrut = strut;
+}
+
+void RenderBlock::setPageY(int y)
+{
+ if (!m_rareData) {
+ if (!y)
+ return;
+ m_rareData = new RenderBlockRareData(this);
+ }
+ m_rareData->m_pageY = y;
}
void RenderBlock::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
@@ -5685,6 +5909,119 @@ RenderBlock* RenderBlock::createAnonymousColumnSpanBlock() const
return newBox;
}
+int RenderBlock::nextPageTop(int yPos) const
+{
+ LayoutState* layoutState = view()->layoutState();
+ if (!layoutState->m_pageHeight)
+ return yPos;
+
+ // The yPos is in our coordinate space. We can add in our pushed offset.
+ int pageHeight = layoutState->m_pageHeight;
+ int remainingHeight = (pageHeight - ((layoutState->m_layoutOffset - layoutState->m_pageOffset).height() + yPos) % pageHeight) % pageHeight;
+ return yPos + remainingHeight;
+}
+
+static bool inNormalFlow(RenderBox* child)
+{
+ RenderBlock* curr = child->containingBlock();
+ RenderBlock* initialBlock = child->view();
+ while (curr && curr != initialBlock) {
+ if (curr->hasColumns())
+ return true;
+ if (curr->isFloatingOrPositioned())
+ return false;
+ curr = curr->containingBlock();
+ }
+ return true;
+}
+
+int RenderBlock::applyBeforeBreak(RenderBox* child, int yPos)
+{
+ // FIXME: Add page break checking here when we support printing.
+ bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
+ bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageHeight; // FIXME: Once columns can print we have to check this.
+ bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS);
+ if (checkBeforeAlways && inNormalFlow(child)) {
+ if (checkColumnBreaks)
+ view()->layoutState()->addForcedColumnBreak(yPos);
+ return nextPageTop(yPos);
+ }
+ return yPos;
+}
+
+int RenderBlock::applyAfterBreak(RenderBox* child, int yPos, MarginInfo& marginInfo)
+{
+ // FIXME: Add page break checking here when we support printing.
+ bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
+ bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageHeight; // FIXME: Once columns can print we have to check this.
+ bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS);
+ if (checkAfterAlways && inNormalFlow(child)) {
+ marginInfo.setBottomQuirk(true); // Cause margins to be discarded for any following content.
+ if (checkColumnBreaks)
+ view()->layoutState()->addForcedColumnBreak(yPos);
+ return nextPageTop(yPos);
+ }
+ return yPos;
+}
+
+int RenderBlock::adjustForUnsplittableChild(RenderBox* child, int yPos, bool includeMargins)
+{
+ bool isUnsplittable = child->isReplaced() || child->scrollsOverflow();
+ if (!isUnsplittable)
+ return yPos;
+ int childHeight = child->height() + (includeMargins ? child->marginTop() + child->marginBottom() : 0);
+ LayoutState* layoutState = view()->layoutState();
+ if (layoutState->m_columnInfo)
+ layoutState->m_columnInfo->updateMinimumColumnHeight(childHeight);
+ int pageHeight = layoutState->m_pageHeight;
+ if (!pageHeight || childHeight > pageHeight)
+ return yPos;
+ int remainingHeight = (pageHeight - ((layoutState->m_layoutOffset - layoutState->m_pageOffset).height() + yPos) % pageHeight) % pageHeight;
+ if (remainingHeight < childHeight)
+ return yPos + remainingHeight;
+ return yPos;
+}
+
+void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, int& delta)
+{
+ // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
+ // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
+ // the line on the top of the next page will appear too far down relative to the same kind of line at the top
+ // of the first column.
+ //
+ // The rendering we would like to see is one where the lineTop is at the top of the column, and any line overflow
+ // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
+ // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
+ // for overflow to occur), and then cache visible overflow for each column rect.
+ //
+ // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
+ // content that paints in a previous column (and content that paints in the following column).
+ //
+ // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
+ // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
+ // line and all following lines.
+ LayoutState* layoutState = view()->layoutState();
+ int pageHeight = layoutState->m_pageHeight;
+ int yPos = lineBox->topVisibleOverflow();
+ int lineHeight = lineBox->bottomVisibleOverflow() - yPos;
+ if (layoutState->m_columnInfo)
+ layoutState->m_columnInfo->updateMinimumColumnHeight(lineHeight);
+ yPos += delta;
+ lineBox->setPaginationStrut(0);
+ if (!pageHeight || lineHeight > pageHeight)
+ return;
+ int remainingHeight = pageHeight - ((layoutState->m_layoutOffset - layoutState->m_pageOffset).height() + yPos) % pageHeight;
+ if (remainingHeight < lineHeight) {
+ int totalHeight = lineHeight + max(0, yPos);
+ if (lineBox == firstRootBox() && totalHeight < pageHeight && !isPositioned() && !isTableCell())
+ setPaginationStrut(remainingHeight + max(0, yPos));
+ else {
+ delta += remainingHeight;
+ lineBox->setPaginationStrut(remainingHeight);
+ }
+ }
+}
+
const char* RenderBlock::renderName() const
{
if (isBody())
diff --git a/WebCore/rendering/RenderBlock.h b/WebCore/rendering/RenderBlock.h
index 6ed0d7b..b26c28c 100644
--- a/WebCore/rendering/RenderBlock.h
+++ b/WebCore/rendering/RenderBlock.h
@@ -34,6 +34,7 @@ namespace WebCore {
class ColumnInfo;
class InlineIterator;
+class LayoutStateMaintainer;
class RenderInline;
struct BidiRun;
@@ -70,7 +71,7 @@ public:
virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0);
virtual void removeChild(RenderObject*);
- virtual void layoutBlock(bool relayoutChildren);
+ virtual void layoutBlock(bool relayoutChildren, int pageHeight = 0);
void insertPositionedObject(RenderBox*);
void removePositionedObject(RenderBox*);
@@ -89,7 +90,15 @@ public:
void markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove = 0, bool inLayout = true);
void markPositionedObjectsForLayout();
-
+ void markForPaginationRelayout()
+ {
+ if (isTable())
+ markDescendantBlocksAndLinesForLayout();
+ else
+ setChildNeedsLayout(true, false);
+ }
+ virtual void markDescendantBlocksAndLinesForLayout(bool inLayout = true);
+
bool containsFloats() { return m_floatingObjects && !m_floatingObjects->isEmpty(); }
bool containsFloat(RenderObject*);
@@ -105,8 +114,9 @@ public:
virtual VisiblePosition positionForPoint(const IntPoint&);
// Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.)
- virtual int availableWidth() const;
-
+ virtual int availableWidth() const; // FIXME: Should be possible to remove this. See https://bugs.webkit.org/show_bug.cgi?id=46127
+ virtual int availableLogicalWidth() const;
+
RootInlineBox* firstRootBox() const { return static_cast<RootInlineBox*>(firstLineBox()); }
RootInlineBox* lastRootBox() const { return static_cast<RootInlineBox*>(lastLineBox()); }
@@ -151,6 +161,15 @@ public:
ColumnInfo* columnInfo() const;
int columnGap() const;
+
+ // These two functions take the ColumnInfo* to avoid repeated lookups of the info in the global HashMap.
+ unsigned columnCount(ColumnInfo*) const;
+ IntRect columnRectAt(ColumnInfo*, unsigned) const;
+
+ int paginationStrut() const { return m_rareData ? m_rareData->m_paginationStrut : 0; }
+ int pageY() const { return m_rareData ? m_rareData->m_pageY : 0; }
+ void setPaginationStrut(int strut);
+ void setPageY(int y);
protected:
// These functions are only used internally to manipulate the render tree structure via remove/insert/appendChildNode.
@@ -177,20 +196,22 @@ protected:
}
void moveChildrenTo(RenderBlock* to, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert = false);
- int maxTopPosMargin() const { return m_maxMargin ? m_maxMargin->m_topPos : MaxMargin::topPosDefault(this); }
- int maxTopNegMargin() const { return m_maxMargin ? m_maxMargin->m_topNeg : MaxMargin::topNegDefault(this); }
- int maxBottomPosMargin() const { return m_maxMargin ? m_maxMargin->m_bottomPos : MaxMargin::bottomPosDefault(this); }
- int maxBottomNegMargin() const { return m_maxMargin ? m_maxMargin->m_bottomNeg : MaxMargin::bottomNegDefault(this); }
+ int maxTopPosMargin() const { return m_rareData ? m_rareData->m_topPos : RenderBlockRareData::topPosDefault(this); }
+ int maxTopNegMargin() const { return m_rareData ? m_rareData->m_topNeg : RenderBlockRareData::topNegDefault(this); }
+ int maxBottomPosMargin() const { return m_rareData ? m_rareData->m_bottomPos : RenderBlockRareData::bottomPosDefault(this); }
+ int maxBottomNegMargin() const { return m_rareData ? m_rareData->m_bottomNeg : RenderBlockRareData::bottomNegDefault(this); }
+
void setMaxTopMargins(int pos, int neg);
void setMaxBottomMargins(int pos, int neg);
-
+
void initMaxMarginValues()
{
- if (m_maxMargin) {
- m_maxMargin->m_topPos = MaxMargin::topPosDefault(this);
- m_maxMargin->m_topNeg = MaxMargin::topNegDefault(this);
- m_maxMargin->m_bottomPos = MaxMargin::bottomPosDefault(this);
- m_maxMargin->m_bottomNeg = MaxMargin::bottomNegDefault(this);
+ if (m_rareData) {
+ m_rareData->m_topPos = RenderBlockRareData::topPosDefault(this);
+ m_rareData->m_topNeg = RenderBlockRareData::topNegDefault(this);
+ m_rareData->m_bottomPos = RenderBlockRareData::bottomPosDefault(this);
+ m_rareData->m_bottomNeg = RenderBlockRareData::bottomNegDefault(this);
+ m_rareData->m_paginationStrut = 0;
}
}
@@ -295,9 +316,42 @@ private:
bool everHadLayout;
};
+ struct FloatingObject : Noncopyable {
+ enum Type {
+ FloatLeft,
+ FloatRight
+ };
+
+ FloatingObject(Type type)
+ : m_renderer(0)
+ , m_top(0)
+ , m_bottom(0)
+ , m_left(0)
+ , m_width(0)
+ , m_paginationStrut(0)
+ , m_type(type)
+ , m_shouldPaint(true)
+ , m_isDescendant(false)
+ {
+ }
+
+ Type type() { return static_cast<Type>(m_type); }
+
+ RenderBox* m_renderer;
+ int m_top;
+ int m_bottom;
+ int m_left;
+ int m_width;
+ int m_paginationStrut;
+ unsigned m_type : 1; // Type (left or right aligned)
+ bool m_shouldPaint : 1;
+ bool m_isDescendant : 1;
+ };
+
// The following functions' implementations are in RenderBlockLineLayout.cpp.
RootInlineBox* determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly,
- InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats);
+ InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats,
+ bool& useRepaintBounds, int& repaintTop, int& repaintBottom);
RootInlineBox* determineEndPosition(RootInlineBox* startBox, InlineIterator& cleanLineStart,
BidiStatus& cleanLineBidiStatus,
int& yPos);
@@ -305,9 +359,9 @@ private:
RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop);
void skipTrailingWhitespace(InlineIterator&, bool isLineEmpty, bool previousLineBrokeCleanly);
- int skipLeadingWhitespace(InlineBidiResolver&, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly);
+ int skipLeadingWhitespace(InlineBidiResolver&, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly, FloatingObject* lastFloatFromPreviousLine);
void fitBelowFloats(int widthToFit, bool firstLine, int& availableWidth);
- InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly, bool& hyphenated, EClear* = 0);
+ InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly, bool& hyphenated, EClear*, FloatingObject* lastFloatFromPreviousLine);
RootInlineBox* constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject);
InlineFlowBox* createLineBoxes(RenderObject*, bool firstLine);
void computeHorizontalPositionsForLine(RootInlineBox*, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&);
@@ -329,12 +383,18 @@ private:
void paintSelection(PaintInfo&, int tx, int ty);
void paintCaret(PaintInfo&, int tx, int ty, CaretType);
- void insertFloatingObject(RenderBox*);
+ FloatingObject* insertFloatingObject(RenderBox*);
void removeFloatingObject(RenderBox*);
-
+ void removeFloatingObjectsBelow(FloatingObject*, int y);
+
// Called from lineWidth, to position the floats added in the last line.
- // Returns ture if and only if it has positioned any floats.
+ // Returns true if and only if it has positioned any floats.
bool positionNewFloats();
+
+ // Positions new floats and also adjust all floats encountered on the line if any of them
+ // have to move to the next page/column.
+ bool positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine);
+
void clearFloats();
int getClearDelta(RenderBox* child, int yPos);
@@ -416,8 +476,7 @@ private:
void offsetForContents(int& tx, int& ty) const;
void calcColumnWidth();
- int layoutColumns(int endOfContent = -1, int requestedColumnHeight = -1);
- int visibleTopOfHighestFloatExtendingBelow(int bottom, int maxHeight) const;
+ bool layoutColumns(bool hasSpecifiedPageHeight, int pageHeight, LayoutStateMaintainer&);
void makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild);
bool expandsToEncloseOverhangingFloats() const;
@@ -433,36 +492,6 @@ private:
RenderBlock* continuationBefore(RenderObject* beforeChild);
RenderBlock* containingColumnsBlock(bool allowAnonymousColumnBlock = true);
RenderBlock* columnsBlockForSpanningElement(RenderObject* newChild);
-
- struct FloatingObject : Noncopyable {
- enum Type {
- FloatLeft,
- FloatRight
- };
-
- FloatingObject(Type type)
- : m_renderer(0)
- , m_top(0)
- , m_bottom(0)
- , m_left(0)
- , m_width(0)
- , m_type(type)
- , m_shouldPaint(true)
- , m_isDescendant(false)
- {
- }
-
- Type type() { return static_cast<Type>(m_type); }
-
- RenderBox* m_renderer;
- int m_top;
- int m_bottom;
- int m_left;
- int m_width;
- unsigned m_type : 1; // Type (left or right aligned)
- bool m_shouldPaint : 1;
- bool m_isDescendant : 1;
- };
class MarginInfo {
// Collapsing flags for whether we can collapse our margins with our children's margins.
@@ -539,6 +568,13 @@ private:
void setCollapsedBottomMargin(const MarginInfo&);
// End helper functions and structs used by layoutBlockChildren.
+ // Pagination routines.
+ int nextPageTop(int yPos) const; // Returns the top of the next page following yPos.
+ int applyBeforeBreak(RenderBox* child, int yPos); // If the child has a before break, then return a new yPos that shifts to the top of the next page/column.
+ int applyAfterBreak(RenderBox* child, int yPos, MarginInfo& marginInfo); // If the child has an after break, then return a new yPos that shifts to the top of the next page/column.
+ int adjustForUnsplittableChild(RenderBox* child, int yPos, bool includeMargins = false); // If the child is unsplittable and can't fit on the current page, return the top of the next page/column.
+ void adjustLinePositionForPagination(RootInlineBox*, int& deltaY); // Computes a deltaY value that put a line at the top of the next page if it doesn't fit on the current page.
+
typedef PositionedObjectsListHashSet::const_iterator Iterator;
DeprecatedPtrList<FloatingObject>* m_floatingObjects;
@@ -551,12 +587,14 @@ private:
RenderBoxModelObject* m_continuation;
// Allocated only when some of these fields have non-default values
- struct MaxMargin : Noncopyable {
- MaxMargin(const RenderBlock* o)
+ struct RenderBlockRareData : Noncopyable {
+ RenderBlockRareData(const RenderBlock* o)
: m_topPos(topPosDefault(o))
, m_topNeg(topNegDefault(o))
, m_bottomPos(bottomPosDefault(o))
, m_bottomNeg(bottomNegDefault(o))
+ , m_paginationStrut(0)
+ , m_pageY(0)
{
}
@@ -564,14 +602,16 @@ private:
static int topNegDefault(const RenderBlock* o) { return o->marginTop() < 0 ? -o->marginTop() : 0; }
static int bottomPosDefault(const RenderBlock* o) { return o->marginBottom() > 0 ? o->marginBottom() : 0; }
static int bottomNegDefault(const RenderBlock* o) { return o->marginBottom() < 0 ? -o->marginBottom() : 0; }
-
+
int m_topPos;
int m_topNeg;
int m_bottomPos;
int m_bottomNeg;
+ int m_paginationStrut;
+ int m_pageY;
};
- MaxMargin* m_maxMargin;
+ OwnPtr<RenderBlockRareData> m_rareData;
RenderObjectChildList m_children;
RenderLineBoxList m_lineBoxes; // All of the root line boxes created for this block flow. For example, <div>Hello<br>world.</div> will have two total lines for the <div>.
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);
diff --git a/WebCore/rendering/RenderBox.cpp b/WebCore/rendering/RenderBox.cpp
index e107c4f..33772a3 100644
--- a/WebCore/rendering/RenderBox.cpp
+++ b/WebCore/rendering/RenderBox.cpp
@@ -980,7 +980,7 @@ void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool
if (RenderView* v = view()) {
if (v->layoutStateEnabled() && !repaintContainer) {
LayoutState* layoutState = v->layoutState();
- IntSize offset = layoutState->m_offset;
+ IntSize offset = layoutState->m_paintOffset;
offset.expand(x(), y());
if (style()->position() == RelativePosition && layer())
offset += layer()->relativePositionOffset();
@@ -1177,7 +1177,7 @@ void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, In
rect.move(layer()->relativePositionOffset());
rect.move(x(), y());
- rect.move(layoutState->m_offset);
+ rect.move(layoutState->m_paintOffset);
if (layoutState->m_clipped)
rect.intersect(layoutState->m_clipRect);
return;
@@ -1584,11 +1584,11 @@ void RenderBox::calcHeight()
// is specified. When we're printing, we also need this quirk if the body or root has a percentage
// height since we don't set a height in RenderView when we're printing. So without this quirk, the
// height has nothing to be a percentage of, and it ends up being 0. That is bad.
- bool paginatedContentNeedsBaseHeight = document()->paginated() && h.isPercent()
+ bool paginatedContentNeedsBaseHeight = document()->printing() && h.isPercent()
&& (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->height().isPercent()));
if (stretchesToViewHeight() || paginatedContentNeedsBaseHeight) {
int margins = collapsedMarginTop() + collapsedMarginBottom();
- int visHeight = document()->printing() ? view()->frameView()->pageHeight() : view()->viewHeight();
+ int visHeight = document()->printing() ? view()->pageHeight() : view()->viewHeight();
if (isRoot())
setHeight(max(height(), visHeight - margins));
else {
@@ -1803,6 +1803,13 @@ int RenderBox::availableHeightUsing(const Length& h) const
return containingBlock()->availableHeight();
}
+int RenderBox::availableLogicalWidth() const
+{
+ if (style()->isVerticalBlockFlow())
+ return contentWidth();
+ return contentHeight();
+}
+
void RenderBox::calcVerticalMargins()
{
if (isTableCell()) {
@@ -2984,4 +2991,19 @@ void RenderBox::clearLayoutOverflow()
m_overflow->resetLayoutOverflow(borderBoxRect());
}
+void RenderBox::markDescendantBlocksAndLinesForLayout(bool inLayout)
+{
+ if (!m_everHadLayout || isReplaced())
+ return;
+
+ setChildNeedsLayout(true, !inLayout);
+
+ // Iterate over our children and mark them as needed.
+ for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+ if (child->isFloatingOrPositioned())
+ continue;
+ child->markDescendantBlocksAndLinesForLayout(inLayout);
+ }
+}
+
} // namespace WebCore
diff --git a/WebCore/rendering/RenderBox.h b/WebCore/rendering/RenderBox.h
index 8f1e9c3..dc1eb96 100644
--- a/WebCore/rendering/RenderBox.h
+++ b/WebCore/rendering/RenderBox.h
@@ -238,9 +238,10 @@ public:
int calcPercentageHeight(const Length& height);
// Block flows subclass availableWidth to handle multi column layout (shrinking the width available to children when laying out.)
- virtual int availableWidth() const { return contentWidth(); }
+ virtual int availableWidth() const { return contentWidth(); } // FIXME: Investigate removing eventually. https://bugs.webkit.org/show_bug.cgi?id=46127
virtual int availableHeight() const;
int availableHeightUsing(const Length&) const;
+ virtual int availableLogicalWidth() const;
void calcVerticalMargins();
@@ -297,10 +298,15 @@ public:
bool shrinkToAvoidFloats() const;
virtual bool avoidsFloats() const;
+<<<<<<< HEAD
#ifdef ANDROID_LAYOUT
int getVisibleWidth() const { return m_visibleWidth; }
#endif
+=======
+ virtual void markDescendantBlocksAndLinesForLayout(bool inLayout = true);
+
+>>>>>>> webkit.org at r67908
protected:
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
diff --git a/WebCore/rendering/RenderBoxModelObject.cpp b/WebCore/rendering/RenderBoxModelObject.cpp
index 0fbc9f2..f4c2d2a 100644
--- a/WebCore/rendering/RenderBoxModelObject.cpp
+++ b/WebCore/rendering/RenderBoxModelObject.cpp
@@ -432,7 +432,7 @@ int RenderBoxModelObject::paddingTop(bool) const
int w = 0;
Length padding = style()->paddingTop();
if (padding.isPercent())
- w = containingBlock()->availableWidth();
+ w = containingBlock()->availableLogicalWidth();
return padding.calcMinValue(w);
}
@@ -441,7 +441,7 @@ int RenderBoxModelObject::paddingBottom(bool) const
int w = 0;
Length padding = style()->paddingBottom();
if (padding.isPercent())
- w = containingBlock()->availableWidth();
+ w = containingBlock()->availableLogicalWidth();
return padding.calcMinValue(w);
}
@@ -450,7 +450,7 @@ int RenderBoxModelObject::paddingLeft(bool) const
int w = 0;
Length padding = style()->paddingLeft();
if (padding.isPercent())
- w = containingBlock()->availableWidth();
+ w = containingBlock()->availableLogicalWidth();
return padding.calcMinValue(w);
}
@@ -459,7 +459,43 @@ int RenderBoxModelObject::paddingRight(bool) const
int w = 0;
Length padding = style()->paddingRight();
if (padding.isPercent())
- w = containingBlock()->availableWidth();
+ w = containingBlock()->availableLogicalWidth();
+ return padding.calcMinValue(w);
+}
+
+int RenderBoxModelObject::paddingBefore(bool) const
+{
+ int w = 0;
+ Length padding = style()->paddingBefore();
+ if (padding.isPercent())
+ w = containingBlock()->availableLogicalWidth();
+ return padding.calcMinValue(w);
+}
+
+int RenderBoxModelObject::paddingAfter(bool) const
+{
+ int w = 0;
+ Length padding = style()->paddingAfter();
+ if (padding.isPercent())
+ w = containingBlock()->availableLogicalWidth();
+ return padding.calcMinValue(w);
+}
+
+int RenderBoxModelObject::paddingStart(bool) const
+{
+ int w = 0;
+ Length padding = style()->paddingStart();
+ if (padding.isPercent())
+ w = containingBlock()->availableLogicalWidth();
+ return padding.calcMinValue(w);
+}
+
+int RenderBoxModelObject::paddingEnd(bool) const
+{
+ int w = 0;
+ Length padding = style()->paddingEnd();
+ if (padding.isPercent())
+ w = containingBlock()->availableLogicalWidth();
return padding.calcMinValue(w);
}
diff --git a/WebCore/rendering/RenderBoxModelObject.h b/WebCore/rendering/RenderBoxModelObject.h
index 49d5f3d..e91e799 100644
--- a/WebCore/rendering/RenderBoxModelObject.h
+++ b/WebCore/rendering/RenderBoxModelObject.h
@@ -70,6 +70,10 @@ public:
virtual int paddingBottom(bool includeIntrinsicPadding = true) const;
virtual int paddingLeft(bool includeIntrinsicPadding = true) const;
virtual int paddingRight(bool includeIntrinsicPadding = true) const;
+ virtual int paddingBefore(bool includeIntrinsicPadding = true) const;
+ virtual int paddingAfter(bool includeIntrinsicPadding = true) const;
+ virtual int paddingStart(bool includeIntrinsicPadding = true) const;
+ virtual int paddingEnd(bool includeIntrinsicPadding = true) const;
virtual int borderTop() const { return style()->borderTopWidth(); }
virtual int borderBottom() const { return style()->borderBottomWidth(); }
diff --git a/WebCore/rendering/RenderEmbeddedObject.cpp b/WebCore/rendering/RenderEmbeddedObject.cpp
index d08174d..4179af3 100644
--- a/WebCore/rendering/RenderEmbeddedObject.cpp
+++ b/WebCore/rendering/RenderEmbeddedObject.cpp
@@ -79,6 +79,10 @@ RenderEmbeddedObject::RenderEmbeddedObject(Element* element)
, m_mouseDownWasInMissingPluginIndicator(false)
{
view()->frameView()->setIsVisuallyNonEmpty();
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ if (element->hasTagName(videoTag) || element->hasTagName(audioTag))
+ setHasIntrinsicSize();
+#endif
}
RenderEmbeddedObject::~RenderEmbeddedObject()
@@ -141,7 +145,7 @@ void RenderEmbeddedObject::paint(PaintInfo& paintInfo, int tx, int ty)
void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
{
- if (pluginCrashedOrWasMissing())
+ if (!pluginCrashedOrWasMissing())
return;
if (paintInfo.phase == PaintPhaseSelection)
diff --git a/WebCore/rendering/RenderFileUploadControl.cpp b/WebCore/rendering/RenderFileUploadControl.cpp
index f31ca20..20ebe4d 100644
--- a/WebCore/rendering/RenderFileUploadControl.cpp
+++ b/WebCore/rendering/RenderFileUploadControl.cpp
@@ -142,11 +142,11 @@ Chrome* RenderFileUploadControl::chrome() const
void RenderFileUploadControl::updateFromElement()
{
HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node());
- ASSERT(inputElement->inputType() == HTMLInputElement::FILE);
+ ASSERT(inputElement->isFileUpload());
if (!m_button) {
m_button = ShadowInputElement::create(inputElement);
- m_button->setInputType("button");
+ m_button->setType("button");
m_button->setValue(fileButtonChooseFileLabel());
RefPtr<RenderStyle> buttonStyle = createButtonStyle(style());
RenderObject* renderer = m_button->createRenderer(renderArena(), buttonStyle.get());
diff --git a/WebCore/rendering/RenderFlexibleBox.cpp b/WebCore/rendering/RenderFlexibleBox.cpp
index 695bd31..659df8d 100644
--- a/WebCore/rendering/RenderFlexibleBox.cpp
+++ b/WebCore/rendering/RenderFlexibleBox.cpp
@@ -206,7 +206,7 @@ void RenderFlexibleBox::calcPrefWidths()
setPrefWidthsDirty(false);
}
-void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
+void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int /*pageHeight FIXME: Implement */)
{
ASSERT(needsLayout());
@@ -286,6 +286,9 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
statePusher.pop();
+ if (view()->layoutState()->m_pageHeight)
+ setPageY(view()->layoutState()->pageY(y()));
+
// Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if
// we overflow or not.
if (hasOverflowClip())
@@ -339,6 +342,8 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
bool haveFlex = false;
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
+ bool paginated = view()->layoutState()->isPaginated();
+
RenderBox* child;
RenderBlock::startDelayUpdateScrollInfo();
@@ -369,6 +374,12 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
// Compute the child's vertical margins.
child->calcVerticalMargins();
+ if (!child->needsLayout() && paginated && view()->layoutState()->m_pageHeight) {
+ RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
+ if (childRenderBlock && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY())
+ childRenderBlock->markForPaginationRelayout();
+ }
+
// Now do the layout.
child->layoutIfNeeded();
@@ -436,6 +447,13 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
child->calcHeight();
if (oldChildHeight != child->height())
child->setChildNeedsLayout(true, false);
+
+ if (!child->needsLayout() && paginated && view()->layoutState()->m_pageHeight) {
+ RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
+ if (childRenderBlock && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY())
+ childRenderBlock->markForPaginationRelayout();
+ }
+
child->layoutIfNeeded();
// We can place the child now, using our value of box-align.
@@ -649,112 +667,15 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
bool haveFlex = false;
gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
+ bool paginated = view()->layoutState()->isPaginated();
+
RenderBox* child;
// We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of
// mainstream block layout); this is not really part of the XUL box model.
bool haveLineClamp = !style()->lineClamp().isNone();
- if (haveLineClamp) {
- int maxLineCount = 0;
- child = iterator.first();
- while (child) {
- if (!child->isPositioned()) {
- if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())) ||
- (child->style()->height().isAuto() && child->isBlockFlow() && !child->needsLayout())) {
- child->setChildNeedsLayout(true, false);
-
- // Dirty all the positioned objects.
- if (child->isRenderBlock()) {
- toRenderBlock(child)->markPositionedObjectsForLayout();
- toRenderBlock(child)->clearTruncation();
- }
- }
- child->layoutIfNeeded();
- if (child->style()->height().isAuto() && child->isBlockFlow())
- maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount());
- }
- child = iterator.next();
- }
-
- // Get the # of lines and then alter all block flow children with auto height to use the
- // specified height. We always try to leave room for at least one line.
- LineClampValue lineClamp = style()->lineClamp();
- int numVisibleLines = lineClamp.isPercentage() ? max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value();
- if (numVisibleLines < maxLineCount) {
- for (child = iterator.first(); child; child = iterator.next()) {
- if (child->isPositioned() || !child->style()->height().isAuto() || !child->isBlockFlow())
- continue;
-
- RenderBlock* blockChild = toRenderBlock(child);
- int lineCount = blockChild->lineCount();
- if (lineCount <= numVisibleLines)
- continue;
-
- int newHeight = blockChild->heightForLineCount(numVisibleLines);
- if (newHeight == child->height())
- continue;
-
- child->setChildNeedsLayout(true, false);
- child->setOverrideSize(newHeight);
- m_flexingChildren = true;
- child->layoutIfNeeded();
- m_flexingChildren = false;
- child->setOverrideSize(-1);
-
- // FIXME: For now don't support RTL.
- if (style()->direction() != LTR)
- continue;
-
- // Get the last line
- RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount-1);
- if (!lastLine)
- continue;
-
- RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines-1);
- if (!lastVisibleLine)
- continue;
-
- const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
- DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
- DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
- const Font& font = style(numVisibleLines == 1)->font();
-
- // Get ellipsis width, and if the last child is an anchor, it will go after the ellipsis, so add in a space and the anchor width too
- int totalWidth;
- InlineBox* anchorBox = lastLine->lastChild();
- if (anchorBox && anchorBox->renderer()->node() && anchorBox->renderer()->node()->isLink())
- totalWidth = anchorBox->width() + font.width(TextRun(ellipsisAndSpace, 2));
- else {
- anchorBox = 0;
- totalWidth = font.width(TextRun(&horizontalEllipsis, 1));
- }
-
- // See if this width can be accommodated on the last visible line
- RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer());
- RenderBlock* srcBlock = toRenderBlock(lastLine->renderer());
-
- // FIXME: Directions of src/destBlock could be different from our direction and from one another.
- if (srcBlock->style()->direction() != LTR)
- continue;
- if (destBlock->style()->direction() != LTR)
- continue;
- int ltr = true;
-
- int blockRightEdge = destBlock->rightOffset(lastVisibleLine->y(), false);
- int blockLeftEdge = destBlock->leftOffset(lastVisibleLine->y(), false);
-
- int blockEdge = ltr ? blockRightEdge : blockLeftEdge;
- if (!lastVisibleLine->canAccommodateEllipsis(ltr, blockEdge,
- lastVisibleLine->x() + lastVisibleLine->width(),
- totalWidth))
- continue;
-
- // Let the truncation code kick in.
- lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, ltr, blockLeftEdge, blockRightEdge, totalWidth, anchorBox);
- destBlock->setHasMarkupTruncation(true);
- }
- }
- }
+ if (haveLineClamp)
+ applyLineClamp(iterator, relayoutChildren);
RenderBlock::startDelayUpdateScrollInfo();
@@ -797,6 +718,12 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
// Add in the child's marginTop to our height.
setHeight(height() + child->marginTop());
+ if (!child->needsLayout() && paginated && view()->layoutState()->m_pageHeight) {
+ RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
+ if (childRenderBlock && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY())
+ childRenderBlock->markForPaginationRelayout();
+ }
+
// Now do a layout.
child->layoutIfNeeded();
@@ -1004,6 +931,109 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
setHeight(oldHeight);
}
+void RenderFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool relayoutChildren)
+{
+ int maxLineCount = 0;
+ RenderBox* child = iterator.first();
+ while (child) {
+ if (!child->isPositioned()) {
+ if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())) ||
+ (child->style()->height().isAuto() && child->isBlockFlow() && !child->needsLayout())) {
+ child->setChildNeedsLayout(true, false);
+
+ // Dirty all the positioned objects.
+ if (child->isRenderBlock()) {
+ toRenderBlock(child)->markPositionedObjectsForLayout();
+ toRenderBlock(child)->clearTruncation();
+ }
+ }
+ child->layoutIfNeeded();
+ if (child->style()->height().isAuto() && child->isBlockFlow())
+ maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount());
+ }
+ child = iterator.next();
+ }
+
+ // Get the # of lines and then alter all block flow children with auto height to use the
+ // specified height. We always try to leave room for at least one line.
+ LineClampValue lineClamp = style()->lineClamp();
+ int numVisibleLines = lineClamp.isPercentage() ? max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value();
+ if (numVisibleLines < maxLineCount) {
+ for (child = iterator.first(); child; child = iterator.next()) {
+ if (child->isPositioned() || !child->style()->height().isAuto() || !child->isBlockFlow())
+ continue;
+
+ RenderBlock* blockChild = toRenderBlock(child);
+ int lineCount = blockChild->lineCount();
+ if (lineCount <= numVisibleLines)
+ continue;
+
+ int newHeight = blockChild->heightForLineCount(numVisibleLines);
+ if (newHeight == child->height())
+ continue;
+
+ child->setChildNeedsLayout(true, false);
+ child->setOverrideSize(newHeight);
+ m_flexingChildren = true;
+ child->layoutIfNeeded();
+ m_flexingChildren = false;
+ child->setOverrideSize(-1);
+
+ // FIXME: For now don't support RTL.
+ if (style()->direction() != LTR)
+ continue;
+
+ // Get the last line
+ RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount-1);
+ if (!lastLine)
+ continue;
+
+ RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines-1);
+ if (!lastVisibleLine)
+ continue;
+
+ const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
+ DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
+ DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
+ const Font& font = style(numVisibleLines == 1)->font();
+
+ // Get ellipsis width, and if the last child is an anchor, it will go after the ellipsis, so add in a space and the anchor width too
+ int totalWidth;
+ InlineBox* anchorBox = lastLine->lastChild();
+ if (anchorBox && anchorBox->renderer()->node() && anchorBox->renderer()->node()->isLink())
+ totalWidth = anchorBox->width() + font.width(TextRun(ellipsisAndSpace, 2));
+ else {
+ anchorBox = 0;
+ totalWidth = font.width(TextRun(&horizontalEllipsis, 1));
+ }
+
+ // See if this width can be accommodated on the last visible line
+ RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer());
+ RenderBlock* srcBlock = toRenderBlock(lastLine->renderer());
+
+ // FIXME: Directions of src/destBlock could be different from our direction and from one another.
+ if (srcBlock->style()->direction() != LTR)
+ continue;
+ if (destBlock->style()->direction() != LTR)
+ continue;
+ int ltr = true;
+
+ int blockRightEdge = destBlock->rightOffset(lastVisibleLine->y(), false);
+ int blockLeftEdge = destBlock->leftOffset(lastVisibleLine->y(), false);
+
+ int blockEdge = ltr ? blockRightEdge : blockLeftEdge;
+ if (!lastVisibleLine->canAccommodateEllipsis(ltr, blockEdge,
+ lastVisibleLine->x() + lastVisibleLine->width(),
+ totalWidth))
+ continue;
+
+ // Let the truncation code kick in.
+ lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, ltr, blockLeftEdge, blockRightEdge, totalWidth, anchorBox);
+ destBlock->setHasMarkupTruncation(true);
+ }
+ }
+}
+
void RenderFlexibleBox::placeChild(RenderBox* child, int x, int y)
{
IntRect oldRect(child->x(), child->y() , child->width(), child->height());
diff --git a/WebCore/rendering/RenderFlexibleBox.h b/WebCore/rendering/RenderFlexibleBox.h
index a0f84ce..2aa20b5 100644
--- a/WebCore/rendering/RenderFlexibleBox.h
+++ b/WebCore/rendering/RenderFlexibleBox.h
@@ -27,6 +27,8 @@
namespace WebCore {
+class FlexBoxIterator;
+
class RenderFlexibleBox : public RenderBlock {
public:
RenderFlexibleBox(Node*);
@@ -38,7 +40,7 @@ public:
void calcHorizontalPrefWidths();
void calcVerticalPrefWidths();
- virtual void layoutBlock(bool relayoutChildren);
+ virtual void layoutBlock(bool relayoutChildren, int pageHeight);
void layoutHorizontalBox(bool relayoutChildren);
void layoutVerticalBox(bool relayoutChildren);
@@ -59,6 +61,9 @@ protected:
bool m_flexingChildren : 1;
bool m_stretchingChildren : 1;
+
+private:
+ void applyLineClamp(FlexBoxIterator&, bool relayoutChildren);
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp
index 316b1cf..d5d52f6 100644
--- a/WebCore/rendering/RenderImage.cpp
+++ b/WebCore/rendering/RenderImage.cpp
@@ -218,9 +218,6 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
int leftPad = paddingLeft();
int topPad = paddingTop();
- if (document()->printing() && !view()->printImages())
- return;
-
GraphicsContext* context = paintInfo.context;
if (!m_imageResource->hasImage() || m_imageResource->errorOccurred()) {
@@ -523,7 +520,7 @@ int RenderImage::calcAspectRatioWidth() const
return 0;
if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
return size.width(); // Don't bother scaling.
- return RenderReplaced::calcReplacedHeight() * size.width() / size.height();
+ return RenderBox::calcReplacedHeight() * size.width() / size.height();
}
int RenderImage::calcAspectRatioHeight() const
@@ -533,27 +530,7 @@ int RenderImage::calcAspectRatioHeight() const
return 0;
if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
return size.height(); // Don't bother scaling.
- return RenderReplaced::calcReplacedWidth() * size.height() / size.width();
-}
-
-void RenderImage::calcPrefWidths()
-{
- ASSERT(prefWidthsDirty());
-
- int borderAndPadding = borderAndPaddingWidth();
- m_maxPrefWidth = calcReplacedWidth(false) + borderAndPadding;
-
- if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength)
- m_maxPrefWidth = min(m_maxPrefWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : 0));
-
- if (style()->width().isPercent() || style()->height().isPercent() ||
- style()->maxWidth().isPercent() || style()->maxHeight().isPercent() ||
- style()->minWidth().isPercent() || style()->minHeight().isPercent())
- m_minPrefWidth = 0;
- else
- m_minPrefWidth = m_maxPrefWidth;
-
- setPrefWidthsDirty(false);
+ return RenderBox::calcReplacedWidth() * size.height() / size.width();
}
} // namespace WebCore
diff --git a/WebCore/rendering/RenderImage.h b/WebCore/rendering/RenderImage.h
index 2b88c32..f9acba8 100644
--- a/WebCore/rendering/RenderImage.h
+++ b/WebCore/rendering/RenderImage.h
@@ -41,7 +41,7 @@ public:
RenderImageResource* imageResource() { return m_imageResource.get(); }
const RenderImageResource* imageResource() const { return m_imageResource.get(); }
- CachedImage* cachedImage() const { return m_imageResource->cachedImage(); }
+ CachedImage* cachedImage() const { return m_imageResource ? m_imageResource->cachedImage() : 0; }
bool setImageSizeForAltText(CachedImage* newImage = 0);
@@ -79,8 +79,6 @@ private:
virtual int calcReplacedWidth(bool includeMaxWidth = true) const;
virtual int calcReplacedHeight() const;
- virtual void calcPrefWidths();
-
int calcAspectRatioWidth() const;
int calcAspectRatioHeight() const;
diff --git a/WebCore/rendering/RenderInline.cpp b/WebCore/rendering/RenderInline.cpp
index e91822e..c985b92 100644
--- a/WebCore/rendering/RenderInline.cpp
+++ b/WebCore/rendering/RenderInline.cpp
@@ -647,7 +647,7 @@ void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer,
LayoutState* layoutState = v->layoutState();
if (style()->position() == RelativePosition && layer())
rect.move(layer()->relativePositionOffset());
- rect.move(layoutState->m_offset);
+ rect.move(layoutState->m_paintOffset);
if (layoutState->m_clipped)
rect.intersect(layoutState->m_clipRect);
return;
@@ -734,7 +734,7 @@ void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b
if (RenderView *v = view()) {
if (v->layoutStateEnabled() && !repaintContainer) {
LayoutState* layoutState = v->layoutState();
- IntSize offset = layoutState->m_offset;
+ IntSize offset = layoutState->m_paintOffset;
if (style()->position() == RelativePosition && layer())
offset += layer()->relativePositionOffset();
transformState.move(offset);
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp
index 63ce830..da6fad1 100644
--- a/WebCore/rendering/RenderLayer.cpp
+++ b/WebCore/rendering/RenderLayer.cpp
@@ -471,7 +471,7 @@ TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavio
void RenderLayer::updatePagination()
{
m_isPaginated = false;
- if (isComposited() || !parent() || renderer()->isPositioned())
+ if (isComposited() || !parent())
return; // FIXME: We will have to deal with paginated compositing layers someday.
// FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though.
@@ -2588,11 +2588,11 @@ void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLaye
columnBlock->layer()->convertToLayerCoords(rootLayer, layerX, layerY);
ColumnInfo* colInfo = columnBlock->columnInfo();
- unsigned colCount = colInfo->columnCount();
+ unsigned colCount = columnBlock->columnCount(colInfo);
int currYOffset = 0;
for (unsigned i = 0; i < colCount; i++) {
// For each rect, we clip to the rect, and then we adjust our coords.
- IntRect colRect = colInfo->columnRectAt(i);
+ IntRect colRect = columnBlock->columnRectAt(colInfo, i);
int currXOffset = colRect.x() - (columnBlock->borderLeft() + columnBlock->paddingLeft());
colRect.move(layerX, layerY);
@@ -3054,17 +3054,17 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend
columnBlock->layer()->convertToLayerCoords(rootLayer, layerX, layerY);
ColumnInfo* colInfo = columnBlock->columnInfo();
- int colCount = colInfo->columnCount();
+ int colCount = columnBlock->columnCount(colInfo);
// We have to go backwards from the last column to the first.
int left = columnBlock->borderLeft() + columnBlock->paddingLeft();
int currYOffset = 0;
int i;
for (i = 0; i < colCount; i++)
- currYOffset -= colInfo->columnRectAt(i).height();
+ currYOffset -= columnBlock->columnRectAt(colInfo, i).height();
for (i = colCount - 1; i >= 0; i--) {
// For each rect, we clip to the rect, and then we adjust our coords.
- IntRect colRect = colInfo->columnRectAt(i);
+ IntRect colRect = columnBlock->columnRectAt(colInfo, i);
int currXOffset = colRect.x() - left;
currYOffset += colRect.height();
colRect.move(layerX, layerY);
diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp
index 480d94b..dbd61e1 100644
--- a/WebCore/rendering/RenderLayerBacking.cpp
+++ b/WebCore/rendering/RenderLayerBacking.cpp
@@ -781,7 +781,17 @@ bool RenderLayerBacking::containsPaintedContent() const
bool RenderLayerBacking::isDirectlyCompositedImage() const
{
RenderObject* renderObject = renderer();
- return renderObject->isImage() && !hasBoxDecorationsOrBackground(renderObject) && !renderObject->hasClip();
+
+ if (!renderObject->isImage() || hasBoxDecorationsOrBackground(renderObject) || renderObject->hasClip())
+ return false;
+
+ RenderImage* imageRenderer = toRenderImage(renderObject);
+ if (CachedImage* cachedImage = imageRenderer->cachedImage()) {
+ if (Image* image = cachedImage->image())
+ return image->isBitmapImage();
+ }
+
+ return false;
}
void RenderLayerBacking::rendererContentChanged()
diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp
index fd38f30..835d21e 100644..100755
--- a/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/WebCore/rendering/RenderLayerCompositor.cpp
@@ -864,6 +864,19 @@ void RenderLayerCompositor::frameViewDidScroll(const IntPoint& scrollPosition)
m_scrollLayer->setPosition(FloatPoint(-scrollPosition.x(), -scrollPosition.y()));
}
+String RenderLayerCompositor::layerTreeAsText()
+{
+ if (compositingLayerUpdatePending())
+ updateCompositingLayers();
+
+ if (!m_rootPlatformLayer)
+ return String();
+
+ // We skip dumping the scroll and clip layers to keep layerTreeAsText output
+ // similar between platforms.
+ return m_rootPlatformLayer->layerTreeAsText();
+}
+
RenderLayerCompositor* RenderLayerCompositor::iframeContentsCompositor(RenderIFrame* renderer)
{
HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(renderer->node());
@@ -1368,16 +1381,9 @@ bool RenderLayerCompositor::needsContentsCompositingLayer(const RenderLayer* lay
bool RenderLayerCompositor::requiresScrollLayer(RootLayerAttachment attachment) const
{
- if (attachment == RootLayerAttachedViaEnclosingIframe)
- return true;
-
-#if PLATFORM(MAC)
- // If we're viewless (i.e. WebKit2), we need to scroll ourselves.
- // FIXME: eventually we should do this on other platforms too.
- if (!m_renderView->frameView()->platformWidget())
- return true;
-#endif
- return false;
+ // We need to handle our own scrolling if we're:
+ return !m_renderView->frameView()->platformWidget() // viewless (i.e. non-Mac, or Mac in WebKit2)
+ || attachment == RootLayerAttachedViaEnclosingIframe; // a composited iframe on Mac
}
void RenderLayerCompositor::ensureRootPlatformLayer()
@@ -1430,10 +1436,6 @@ void RenderLayerCompositor::ensureRootPlatformLayer()
}
}
- // The root layer does geometry flipping if we need it.
- m_rootPlatformLayer->setGeometryOrientation(expectedAttachment == RootLayerAttachedViaEnclosingIframe
- ? GraphicsLayer::CompositingCoordinatesTopDown : GraphicsLayer::compositingCoordinatesOrientation());
-
// Check to see if we have to change the attachment
if (m_rootLayerAttachment != RootLayerUnattached)
detachRootPlatformLayer();
diff --git a/WebCore/rendering/RenderLayerCompositor.h b/WebCore/rendering/RenderLayerCompositor.h
index 86c061b..b4e3afe 100644..100755
--- a/WebCore/rendering/RenderLayerCompositor.h
+++ b/WebCore/rendering/RenderLayerCompositor.h
@@ -166,6 +166,8 @@ public:
void frameViewDidChangeSize(const IntPoint& contentsOffset = IntPoint());
void frameViewDidScroll(const IntPoint& = IntPoint());
+ String layerTreeAsText();
+
private:
// Whether the given RL needs a compositing layer.
bool needsToBeComposited(const RenderLayer*) const;
diff --git a/WebCore/rendering/RenderLineBoxList.cpp b/WebCore/rendering/RenderLineBoxList.cpp
index 4d0dcd6..45e66eb 100644
--- a/WebCore/rendering/RenderLineBoxList.cpp
+++ b/WebCore/rendering/RenderLineBoxList.cpp
@@ -35,7 +35,6 @@
#include "RenderInline.h"
#include "RenderView.h"
#include "RootInlineBox.h"
-#include "Settings.h" // FIXME: This include can be removed when paginateDuringLayoutEnabled is taken out.
using namespace std;
@@ -160,8 +159,10 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintIn
if (!firstLineBox())
return;
+ // FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
+ // NSViews. Do not add any more code for this.
RenderView* v = renderer->view();
- bool usePrintRect = !v->printRect().isEmpty() && !renderer->document()->settings()->paginateDuringLayoutEnabled();
+ bool usePrintRect = !v->printRect().isEmpty();
// We can check the first box and last box and avoid painting if we don't
// intersect. This is a quick short-circuit that we can take to avoid walking any lines.
@@ -215,7 +216,6 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintIn
int bottom = curr->bottomVisibleOverflow() + renderer->maximalOutlineSize(info.phase);
h = bottom - top;
yPos = ty + top;
- v->setMinimumColumnHeight(h);
if (yPos < info.rect.bottom() && yPos + h > info.rect.y())
curr->paint(info, tx, ty);
}
diff --git a/WebCore/rendering/RenderMediaControls.cpp b/WebCore/rendering/RenderMediaControls.cpp
index f75da70..9c4757c 100644
--- a/WebCore/rendering/RenderMediaControls.cpp
+++ b/WebCore/rendering/RenderMediaControls.cpp
@@ -29,44 +29,51 @@
#include "GraphicsContext.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
-#include "RenderThemeSafari.h"
-#include "SoftLinking.h"
+#include "RenderTheme.h"
#include <CoreGraphics/CoreGraphics.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+
+#if PLATFORM(WIN)
+// The Windows version of WKSI defines these functions as capitalized, while the Mac version defines them as lower case.
+#define wkMediaControllerThemeAvailable(themeStyle) WKMediaControllerThemeAvailable(themeStyle)
+#define wkHitTestMediaUIPart(part, themeStyle, bounds, point) WKHitTestMediaUIPart(part, themeStyle, bounds, point)
+#define wkMeasureMediaUIPart(part, themeStyle, bounds, naturalSize) WKMeasureMediaUIPart(part, themeStyle, bounds, naturalSize)
+#define wkDrawMediaUIPart(part, themeStyle, context, rect, state) WKDrawMediaUIPart(part, themeStyle, context, rect, state)
+#define wkDrawMediaSliderTrack(themeStyle, context, rect, timeLoaded, currentTime, duration, state) WKDrawMediaSliderTrack(themeStyle, context, rect, timeLoaded, currentTime, duration, state)
+#endif
using namespace std;
namespace WebCore {
-#ifdef DEBUG_ALL
-SOFT_LINK_DEBUG_LIBRARY(SafariTheme)
-#else
-SOFT_LINK_LIBRARY(SafariTheme)
-#endif
-
-SOFT_LINK(SafariTheme, paintThemePart, void, __stdcall, (ThemePart part, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state), (part, context, rect, size, state))
-SOFT_LINK(SafariTheme, STPaintProgressIndicator, void, APIENTRY, (ProgressIndicatorType type, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state, float value), (type, context, rect, size, state, value))
-
#if ENABLE(VIDEO)
-static ThemeControlState determineState(RenderObject* o)
+static WKMediaControllerThemeState determineState(RenderObject* o)
{
- ThemeControlState result = 0;
+ int result = 0;
RenderTheme* theme = o->theme();
- if (theme->isActive(o))
- result |= SafariTheme::ActiveState;
- if (theme->isEnabled(o) && !theme->isReadOnlyControl(o))
- result |= SafariTheme::EnabledState;
+ if (!theme->isEnabled(o) || theme->isReadOnlyControl(o))
+ result |= WKMediaControllerFlagDisabled;
if (theme->isPressed(o))
- result |= SafariTheme::PressedState;
- if (theme->isChecked(o))
- result |= SafariTheme::CheckedState;
- if (theme->isIndeterminate(o))
- result |= SafariTheme::IndeterminateCheckedState;
+ result |= WKMediaControllerFlagPressed;
if (theme->isFocused(o))
- result |= SafariTheme::FocusedState;
- if (theme->isDefault(o))
- result |= SafariTheme::DefaultState;
- return result;
+ result |= WKMediaControllerFlagFocused;
+ return static_cast<WKMediaControllerThemeState>(result);
+}
+
+// Utility to scale when the UI part are not scaled by wkDrawMediaUIPart
+static FloatRect getUnzoomedRectAndAdjustCurrentContext(RenderObject* o, const PaintInfo& paintInfo, const IntRect &originalRect)
+{
+ float zoomLevel = o->style()->effectiveZoom();
+ FloatRect unzoomedRect(originalRect);
+ if (zoomLevel != 1.0f) {
+ unzoomedRect.setWidth(unzoomedRect.width() / zoomLevel);
+ unzoomedRect.setHeight(unzoomedRect.height() / zoomLevel);
+ paintInfo.context->translate(unzoomedRect.x(), unzoomedRect.y());
+ paintInfo.context->scale(FloatSize(zoomLevel, zoomLevel));
+ paintInfo.context->translate(-unzoomedRect.x(), -unzoomedRect.y());
+ }
+ return unzoomedRect;
}
static const int mediaSliderThumbWidth = 13;
@@ -74,73 +81,78 @@ static const int mediaSliderThumbHeight = 14;
void RenderMediaControls::adjustMediaSliderThumbSize(RenderObject* o)
{
- if (o->style()->appearance() != MediaSliderThumbPart)
+ ControlPart part = o->style()->appearance();
+
+ if (part != MediaSliderThumbPart && part != MediaVolumeSliderThumbPart)
return;
+ CGSize size;
+ wkMeasureMediaUIPart(part == MediaSliderThumbPart ? MediaSliderThumb : MediaVolumeSliderThumb, WKMediaControllerThemeQuickTime, 0, &size);
+
float zoomLevel = o->style()->effectiveZoom();
- o->style()->setWidth(Length(static_cast<int>(mediaSliderThumbWidth * zoomLevel), Fixed));
- o->style()->setHeight(Length(static_cast<int>(mediaSliderThumbHeight * zoomLevel), Fixed));
+ o->style()->setWidth(Length(static_cast<int>(size.width * zoomLevel), Fixed));
+ o->style()->setHeight(Length(static_cast<int>(size.height * zoomLevel), Fixed));
}
bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
- ASSERT(SafariThemeLibrary());
-
+ static const int themeStyle = WKMediaControllerThemeQuickTime;
+ paintInfo.context->save();
switch (part) {
case MediaFullscreenButton:
- paintThemePart(SafariTheme::MediaFullscreenButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+ wkDrawMediaUIPart(WKMediaUIPartFullscreenButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
break;
case MediaShowClosedCaptionsButton:
case MediaHideClosedCaptionsButton:
-#if SAFARI_THEME_VERSION >= 4
if (MediaControlToggleClosedCaptionsButtonElement* btn = static_cast<MediaControlToggleClosedCaptionsButtonElement*>(o->node())) {
bool captionsVisible = btn->displayType() == MediaHideClosedCaptionsButton;
- paintThemePart(captionsVisible ? SafariTheme::MediaHideClosedCaptionsButtonPart : SafariTheme::MediaShowClosedCaptionsButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+ wkDrawMediaUIPart(captionsVisible ? WKMediaUIPartHideClosedCaptionsButton : WKMediaUIPartShowClosedCaptionsButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
}
-#endif
break;
case MediaMuteButton:
case MediaUnMuteButton:
if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(o->node())) {
bool audioEnabled = btn->displayType() == MediaMuteButton;
- paintThemePart(audioEnabled ? SafariTheme::MediaMuteButtonPart : SafariTheme::MediaUnMuteButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+ wkDrawMediaUIPart(audioEnabled ? WKMediaUIPartMuteButton : WKMediaUIPartUnMuteButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
}
break;
case MediaPauseButton:
case MediaPlayButton:
if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o->node())) {
bool canPlay = btn->displayType() == MediaPlayButton;
- paintThemePart(canPlay ? SafariTheme::MediaPlayButtonPart : SafariTheme::MediaPauseButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+ wkDrawMediaUIPart(canPlay ? WKMediaUIPartPlayButton : WKMediaUIPartPauseButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
}
break;
+ case MediaRewindButton:
+ wkDrawMediaUIPart(WKMediaUIPartRewindButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
+ break;
case MediaSeekBackButton:
- paintThemePart(SafariTheme::MediaSeekBackButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+ wkDrawMediaUIPart(WKMediaUIPartSeekBackButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
break;
case MediaSeekForwardButton:
- paintThemePart(SafariTheme::MediaSeekForwardButtonPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+ wkDrawMediaUIPart(WKMediaUIPartSeekForwardButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
break;
case MediaSlider: {
- if (HTMLMediaElement* mediaElement = toParentMediaElement(o))
- STPaintProgressIndicator(SafariTheme::MediaType, paintInfo.context->platformContext(), r, NSRegularControlSize, 0, mediaElement->percentLoaded());
+ if (HTMLMediaElement* mediaElement = toParentMediaElement(o)) {
+ FloatRect unzoomedRect = getUnzoomedRectAndAdjustCurrentContext(o, paintInfo, r);
+ wkDrawMediaSliderTrack(themeStyle, paintInfo.context->platformContext(), unzoomedRect, mediaElement->percentLoaded() * mediaElement->duration(), mediaElement->currentTime(), mediaElement->duration(), determineState(o));
+ }
break;
}
case MediaSliderThumb:
- paintThemePart(SafariTheme::MediaSliderThumbPart, paintInfo.context->platformContext(), r, NSRegularControlSize, determineState(o));
+ wkDrawMediaUIPart(WKMediaUIPartTimelineSliderThumb, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
break;
case MediaVolumeSliderContainer:
- // FIXME: Implement volume slider.
- ASSERT_NOT_REACHED();
+ wkDrawMediaUIPart(WKMediaUIPartVolumeSliderContainer, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
break;
case MediaVolumeSlider:
- // FIXME: Implement volume slider.
- ASSERT_NOT_REACHED();
+ wkDrawMediaUIPart(WKMediaUIPartVolumeSlider, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
break;
case MediaVolumeSliderThumb:
- // FIXME: Implement volume slider.
- ASSERT_NOT_REACHED();
+ wkDrawMediaUIPart(WKMediaUIPartVolumeSliderThumb, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
break;
case MediaTimelineContainer:
- ASSERT_NOT_REACHED();
+ wkDrawMediaUIPart(WKMediaUIPartBackground, themeStyle, paintInfo.context->platformContext(), r, determineState(o));
break;
case MediaCurrentTimeDisplay:
ASSERT_NOT_REACHED();
@@ -152,9 +164,24 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R
ASSERT_NOT_REACHED();
break;
}
+ paintInfo.context->restore();
+
return false;
}
+IntPoint RenderMediaControls::volumeSliderOffsetFromMuteButton(Node* muteButton, const IntSize& size)
+{
+ static const int xOffset = -4;
+ static const int yOffset = 5;
+
+ float zoomLevel = muteButton->renderer()->style()->effectiveZoom();
+ int y = yOffset * zoomLevel + muteButton->renderBox()->offsetHeight() - size.height();
+ FloatPoint absPoint = muteButton->renderer()->localToAbsolute(FloatPoint(muteButton->renderBox()->offsetLeft(), y), true, true);
+ if (absPoint.y() < 0)
+ y = muteButton->renderBox()->height();
+ return IntPoint(xOffset * zoomLevel, y);
+
+}
#endif // #if ENABLE(VIDEO)
} // namespace WebCore
diff --git a/WebCore/rendering/RenderMediaControls.h b/WebCore/rendering/RenderMediaControls.h
index 9683dd7..f05c549 100644
--- a/WebCore/rendering/RenderMediaControls.h
+++ b/WebCore/rendering/RenderMediaControls.h
@@ -36,6 +36,7 @@ class RenderMediaControls {
public:
static bool paintMediaControlsPart(MediaControlElementType, RenderObject*, const PaintInfo&, const IntRect&);
static void adjustMediaSliderThumbSize(RenderObject*);
+ static IntPoint volumeSliderOffsetFromMuteButton(Node*, const IntSize&);
};
} // namespace WebCore
diff --git a/WebCore/rendering/RenderObject.h b/WebCore/rendering/RenderObject.h
index c369db8..f2ca471 100644
--- a/WebCore/rendering/RenderObject.h
+++ b/WebCore/rendering/RenderObject.h
@@ -316,6 +316,7 @@ public:
virtual bool isSVGHiddenContainer() const { return false; }
virtual bool isRenderPath() const { return false; }
virtual bool isSVGText() const { return false; }
+ virtual bool isSVGInline() const { return false; }
virtual bool isSVGInlineText() const { return false; }
virtual bool isSVGImage() const { return false; }
virtual bool isSVGForeignObject() const { return false; }
@@ -988,14 +989,7 @@ inline void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRenderi
inline int adjustForAbsoluteZoom(int value, RenderObject* renderer)
{
- double zoomFactor = renderer->style()->effectiveZoom();
- if (zoomFactor == 1)
- return value;
- // Needed because computeLengthInt truncates (rather than rounds) when scaling up.
- if (zoomFactor > 1)
- value++;
-
- return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(value / zoomFactor);
+ return adjustForAbsoluteZoom(value, renderer->style());
}
inline void adjustIntRectForAbsoluteZoom(IntRect& rect, RenderObject* renderer)
diff --git a/WebCore/rendering/RenderReplaced.cpp b/WebCore/rendering/RenderReplaced.cpp
index 0da321e..b54a228 100644
--- a/WebCore/rendering/RenderReplaced.cpp
+++ b/WebCore/rendering/RenderReplaced.cpp
@@ -40,6 +40,7 @@ const int cDefaultHeight = 150;
RenderReplaced::RenderReplaced(Node* node)
: RenderBox(node)
, m_intrinsicSize(cDefaultWidth, cDefaultHeight)
+ , m_hasIntrinsicSize(false)
{
setReplaced(true);
}
@@ -47,6 +48,7 @@ RenderReplaced::RenderReplaced(Node* node)
RenderReplaced::RenderReplaced(Node* node, const IntSize& intrinsicSize)
: RenderBox(node)
, m_intrinsicSize(intrinsicSize)
+ , m_hasIntrinsicSize(true)
{
setReplaced(true);
}
@@ -192,21 +194,78 @@ bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, int& tx, int& ty)
return true;
}
+static inline bool lengthIsSpecified(Length length)
+{
+ LengthType lengthType = length.type();
+ return lengthType == Fixed || lengthType == Percent;
+}
+
+int RenderReplaced::calcReplacedWidth(bool includeMaxWidth) const
+{
+ int width;
+ if (lengthIsSpecified(style()->width()))
+ width = calcReplacedWidthUsing(style()->width());
+ else if (m_hasIntrinsicSize)
+ width = calcAspectRatioWidth();
+ else
+ width = intrinsicSize().width();
+
+ int minW = calcReplacedWidthUsing(style()->minWidth());
+ int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth());
+
+ return max(minW, min(width, maxW));
+}
+
+int RenderReplaced::calcReplacedHeight() const
+{
+ int height;
+ if (lengthIsSpecified(style()->height()))
+ height = calcReplacedHeightUsing(style()->height());
+ else if (m_hasIntrinsicSize)
+ height = calcAspectRatioHeight();
+ else
+ height = intrinsicSize().height();
+
+ int minH = calcReplacedHeightUsing(style()->minHeight());
+ int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight());
+
+ return max(minH, min(height, maxH));
+}
+
+int RenderReplaced::calcAspectRatioWidth() const
+{
+ int intrinsicWidth = intrinsicSize().width();
+ int intrinsicHeight = intrinsicSize().height();
+ if (!intrinsicHeight)
+ return 0;
+ return RenderBox::calcReplacedHeight() * intrinsicWidth / intrinsicHeight;
+}
+
+int RenderReplaced::calcAspectRatioHeight() const
+{
+ int intrinsicWidth = intrinsicSize().width();
+ int intrinsicHeight = intrinsicSize().height();
+ if (!intrinsicWidth)
+ return 0;
+ return RenderBox::calcReplacedWidth() * intrinsicHeight / intrinsicWidth;
+}
+
void RenderReplaced::calcPrefWidths()
{
ASSERT(prefWidthsDirty());
int borderAndPadding = borderAndPaddingWidth();
- int width = calcReplacedWidth(false) + borderAndPadding;
+ m_maxPrefWidth = calcReplacedWidth(false) + borderAndPadding;
if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength)
- width = min(width, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : 0));
+ m_maxPrefWidth = min(m_maxPrefWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : 0));
- if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent())) {
+ if (style()->width().isPercent() || style()->height().isPercent()
+ || style()->maxWidth().isPercent() || style()->maxHeight().isPercent()
+ || style()->minWidth().isPercent() || style()->minHeight().isPercent())
m_minPrefWidth = 0;
- m_maxPrefWidth = width;
- } else
- m_minPrefWidth = m_maxPrefWidth = width;
+ else
+ m_minPrefWidth = m_maxPrefWidth;
setPrefWidthsDirty(false);
}
@@ -329,6 +388,7 @@ IntSize RenderReplaced::intrinsicSize() const
void RenderReplaced::setIntrinsicSize(const IntSize& size)
{
+ ASSERT(m_hasIntrinsicSize);
m_intrinsicSize = size;
}
diff --git a/WebCore/rendering/RenderReplaced.h b/WebCore/rendering/RenderReplaced.h
index b5c6179..8a0543c 100644
--- a/WebCore/rendering/RenderReplaced.h
+++ b/WebCore/rendering/RenderReplaced.h
@@ -37,6 +37,10 @@ protected:
virtual IntSize intrinsicSize() const;
+ virtual int calcReplacedWidth(bool includeMaxWidth = true) const;
+ virtual int calcReplacedHeight() const;
+ virtual int minimumReplacedHeight() const { return 0; }
+
virtual void setSelectionState(SelectionState);
bool isSelected() const;
@@ -45,6 +49,7 @@ protected:
void setIntrinsicSize(const IntSize&);
virtual void intrinsicSizeChanged();
+ void setHasIntrinsicSize() { m_hasIntrinsicSize = true; }
virtual void paint(PaintInfo&, int tx, int ty);
bool shouldPaint(PaintInfo&, int& tx, int& ty);
@@ -60,7 +65,8 @@ private:
virtual void calcPrefWidths();
- virtual int minimumReplacedHeight() const { return 0; }
+ int calcAspectRatioWidth() const;
+ int calcAspectRatioHeight() const;
virtual void paintReplaced(PaintInfo&, int /*tx*/, int /*ty*/) { }
@@ -74,6 +80,7 @@ private:
virtual IntRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent = true);
IntSize m_intrinsicSize;
+ bool m_hasIntrinsicSize;
};
}
diff --git a/WebCore/rendering/RenderSVGInline.h b/WebCore/rendering/RenderSVGInline.h
index fb38f1b..92b6fe7 100644
--- a/WebCore/rendering/RenderSVGInline.h
+++ b/WebCore/rendering/RenderSVGInline.h
@@ -37,6 +37,7 @@ public:
virtual const char* renderName() const { return "RenderSVGInline"; }
virtual bool requiresLayer() const { return false; }
+ virtual bool isSVGInline() const { return true; }
// Chapter 10.4 of the SVG Specification say that we should use the
// object bounding box of the parent text element.
diff --git a/WebCore/rendering/RenderSVGInlineText.cpp b/WebCore/rendering/RenderSVGInlineText.cpp
index ba99243..0539d27 100644
--- a/WebCore/rendering/RenderSVGInlineText.cpp
+++ b/WebCore/rendering/RenderSVGInlineText.cpp
@@ -65,6 +65,47 @@ IntRect RenderSVGInlineText::localCaretRect(InlineBox*, int, int*)
return IntRect();
}
+IntRect RenderSVGInlineText::linesBoundingBox() const
+{
+ IntRect boundingBox;
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
+ boundingBox.unite(box->calculateBoundaries());
+ return boundingBox;
+}
+
+bool RenderSVGInlineText::characterStartsNewTextChunk(int position) const
+{
+ ASSERT(m_attributes.xValues().size() == textLength());
+ ASSERT(m_attributes.yValues().size() == textLength());
+ ASSERT(position >= 0);
+ ASSERT(position < static_cast<int>(textLength()));
+
+ int currentPosition = 0;
+ unsigned size = m_attributes.characterDataValues().size();
+ for (unsigned i = 0; i < size; ++i) {
+ const SVGTextLayoutAttributes::CharacterData& data = m_attributes.characterDataValues().at(i);
+
+ // We found the desired character.
+ if (currentPosition == position) {
+ if (isVerticalWritingMode(style()->svgStyle()))
+ return m_attributes.yValues().at(position) != SVGTextLayoutAttributes::emptyValue();
+
+ return m_attributes.xValues().at(position) != SVGTextLayoutAttributes::emptyValue();
+ }
+
+ currentPosition += data.spansCharacters;
+ if (currentPosition > position)
+ break;
+ }
+
+ // The desired position is available in the x/y list, but not in the character data values list.
+ // That means the previous character data described a single glyph, consisting of multiple unicode characters.
+ // The consequence is that the desired character does not define a new absolute x/y position, even if present in the x/y test.
+ // This code is tested by svg/W3C-SVG-1.1/text-text-06-t.svg (and described in detail, why this influences chunk detection).
+ ASSERT(currentPosition > position);
+ return false;
+}
+
}
#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/RenderSVGInlineText.h b/WebCore/rendering/RenderSVGInlineText.h
index 08b4a47..f606918 100644
--- a/WebCore/rendering/RenderSVGInlineText.h
+++ b/WebCore/rendering/RenderSVGInlineText.h
@@ -26,14 +26,18 @@
#define RenderSVGInlineText_h
#if ENABLE(SVG)
-
#include "RenderText.h"
+#include "SVGTextLayoutAttributes.h"
namespace WebCore {
+
class RenderSVGInlineText : public RenderText {
public:
RenderSVGInlineText(Node*, PassRefPtr<StringImpl>);
+ bool characterStartsNewTextChunk(int position) const;
+ void storeLayoutAttributes(const SVGTextLayoutAttributes& attributes) { m_attributes = attributes; }
+
private:
virtual const char* renderName() const { return "RenderSVGInlineText"; }
@@ -47,8 +51,10 @@ private:
virtual bool isSVGInlineText() const { return true; }
virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
-
+ virtual IntRect linesBoundingBox() const;
virtual InlineTextBox* createTextBox();
+
+ SVGTextLayoutAttributes m_attributes;
};
}
diff --git a/WebCore/rendering/RenderSVGResourceFilter.cpp b/WebCore/rendering/RenderSVGResourceFilter.cpp
index 982375e..698033e 100644
--- a/WebCore/rendering/RenderSVGResourceFilter.cpp
+++ b/WebCore/rendering/RenderSVGResourceFilter.cpp
@@ -1,8 +1,8 @@
/*
* Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
- * 2004, 2005 Rob Buis <buis@kde.org>
- * 2005 Eric Seidel <eric@webkit.org>
- * 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
+ * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -19,7 +19,6 @@
* 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"
@@ -193,12 +192,12 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*,
if (!lastEffect)
return false;
- lastEffect->calculateEffectRect(filterData->filter.get());
+ lastEffect->determineFilterPrimitiveSubregion(filterData->filter.get());
// At least one FilterEffect has a too big image size,
// recalculate the effect sizes with new scale factors.
if (!fitsInMaximumImageSize(filterData->filter->maxImageSize(), scale)) {
filterData->filter->setFilterResolution(scale);
- lastEffect->calculateEffectRect(filterData->filter.get());
+ lastEffect->determineFilterPrimitiveSubregion(filterData->filter.get());
}
clippedSourceRect.scale(scale.width(), scale.height());
@@ -255,7 +254,7 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo
FilterEffect* lastEffect = filterData->builder->lastEffect();
- if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->subRegion().isEmpty()) {
+ if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPrimitiveSubregion().isEmpty()) {
// This is the real filtering of the object. It just needs to be called on the
// initial filtering process. We just take the stored filter result on a
// second drawing.
@@ -272,7 +271,7 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo
ImageBuffer* resultImage = lastEffect->resultImage();
if (resultImage)
- context->drawImageBuffer(resultImage, object->style()->colorSpace(), lastEffect->subRegion());
+ context->drawImageBuffer(resultImage, object->style()->colorSpace(), lastEffect->filterPrimitiveSubregion());
}
filterData->sourceGraphicBuffer.clear();
diff --git a/WebCore/rendering/RenderSVGText.cpp b/WebCore/rendering/RenderSVGText.cpp
index 80b8a91..c20a509 100644
--- a/WebCore/rendering/RenderSVGText.cpp
+++ b/WebCore/rendering/RenderSVGText.cpp
@@ -42,6 +42,7 @@
#include "SVGRenderSupport.h"
#include "SVGRootInlineBox.h"
#include "SVGTextElement.h"
+#include "SVGTextLayoutBuilder.h"
#include "SVGTransformList.h"
#include "SVGURIReference.h"
#include "SimpleFontData.h"
@@ -83,6 +84,9 @@ void RenderSVGText::layout()
updateCachedBoundariesInParents = true;
}
+ SVGTextLayoutBuilder layoutBuilder;
+ layoutBuilder.buildLayoutAttributesForTextSubtree(this);
+
// Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text.
// All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions.
ASSERT(!isInline());
diff --git a/WebCore/rendering/RenderSlider.cpp b/WebCore/rendering/RenderSlider.cpp
index aef807b..39ac2e5 100644
--- a/WebCore/rendering/RenderSlider.cpp
+++ b/WebCore/rendering/RenderSlider.cpp
@@ -29,7 +29,7 @@
#include "Frame.h"
#include "HTMLInputElement.h"
#include "HTMLNames.h"
-#include "HTMLTreeBuilder.h"
+#include "HTMLParserIdioms.h"
#include "MediaControlElements.h"
#include "MouseEvent.h"
#include "RenderLayer.h"
diff --git a/WebCore/rendering/RenderTable.cpp b/WebCore/rendering/RenderTable.cpp
index 48f3920..124dacb 100644
--- a/WebCore/rendering/RenderTable.cpp
+++ b/WebCore/rendering/RenderTable.cpp
@@ -62,11 +62,16 @@ RenderTable::RenderTable(Node* node)
, m_borderLeft(0)
, m_borderRight(0)
{
+<<<<<<< HEAD
#ifdef ANDROID_LAYOUT
m_singleColumn = false;
#endif
+=======
+ setChildrenInline(false);
+>>>>>>> webkit.org at r67908
m_columnPos.fill(0, 2);
m_columns.fill(ColumnStruct(), 1);
+
}
void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
@@ -458,6 +463,9 @@ void RenderTable::layout()
statePusher.pop();
+ if (view()->layoutState()->m_pageHeight)
+ setPageY(view()->layoutState()->pageY(y()));
+
bool didFullRepaint = repainter.repaintAfterLayout();
// Repaint with our new bounds if they are different from our old bounds.
if (!didFullRepaint && sectionMoved)
diff --git a/WebCore/rendering/RenderTableCell.cpp b/WebCore/rendering/RenderTableCell.cpp
index c0532cf..add2b5e 100644
--- a/WebCore/rendering/RenderTableCell.cpp
+++ b/WebCore/rendering/RenderTableCell.cpp
@@ -304,34 +304,53 @@ void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* ol
// (4) If border styles differ only in color, then a style set on a cell wins over one on a row,
// which wins over a row group, column, column group and, lastly, table. It is undefined which color
// is used when two elements of the same type disagree.
-static CollapsedBorderValue compareBorders(const CollapsedBorderValue& border1, const CollapsedBorderValue& border2)
+static int compareBorders(const CollapsedBorderValue& border1, const CollapsedBorderValue& border2)
{
- // Sanity check the values passed in. If either is null, return the other.
- if (!border2.exists())
- return border1;
+ // Sanity check the values passed in. The null border have lowest priority.
+ if (!border2.exists()) {
+ if (!border1.exists())
+ return 0;
+ return 1;
+ }
if (!border1.exists())
- return border2;
+ return -1;
// Rule #1 above.
- if (border1.style() == BHIDDEN || border2.style() == BHIDDEN)
- return CollapsedBorderValue(); // No border should exist at this location.
+ if (border2.style() == BHIDDEN) {
+ if (border1.style() == BHIDDEN)
+ return 0;
+ return -1;
+ }
+ if (border1.style() == BHIDDEN)
+ return 1;
// Rule #2 above. A style of 'none' has lowest priority and always loses to any other border.
- if (border2.style() == BNONE)
- return border1;
+ if (border2.style() == BNONE) {
+ if (border1.style() == BNONE)
+ return 0;
+ return 1;
+ }
if (border1.style() == BNONE)
- return border2;
+ return -1;
// The first part of rule #3 above. Wider borders win.
if (border1.width() != border2.width())
- return border1.width() > border2.width() ? border1 : border2;
+ return border1.width() < border2.width() ? -1 : 1;
// The borders have equal width. Sort by border style.
if (border1.style() != border2.style())
- return border1.style() > border2.style() ? border1 : border2;
+ return border1.style() < border2.style() ? -1 : 1;
// The border have the same width and style. Rely on precedence (cell over row over row group, etc.)
- return border1.precedence() >= border2.precedence() ? border1 : border2;
+ if (border1.precedence() == border2.precedence())
+ return 0;
+ return border1.precedence() < border2.precedence() ? -1 : 1;
+}
+
+static CollapsedBorderValue chooseBorder(const CollapsedBorderValue& border1, const CollapsedBorderValue& border2)
+{
+ const CollapsedBorderValue& border = compareBorders(border1, border2) < 0 ? border2 : border1;
+ return border.style() == BHIDDEN ? CollapsedBorderValue() : border;
}
CollapsedBorderValue RenderTableCell::collapsedLeftBorder(bool rtl) const
@@ -355,17 +374,17 @@ CollapsedBorderValue RenderTableCell::collapsedLeftBorder(bool rtl) const
RenderTableCell* prevCell = rtl ? tableElt->cellAfter(this) : tableElt->cellBefore(this);
if (prevCell) {
CollapsedBorderValue prevCellBorder = CollapsedBorderValue(&prevCell->style()->borderRight(), prevCell->style()->visitedDependentColor(right), BCELL);
- result = rtl ? compareBorders(result, prevCellBorder) : compareBorders(prevCellBorder, result);
+ result = rtl ? chooseBorder(result, prevCellBorder) : chooseBorder(prevCellBorder, result);
if (!result.exists())
return result;
} else if (leftmostColumn) {
// (3) Our row's left border.
- result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderLeft(), parent()->style()->visitedDependentColor(left), BROW));
+ result = chooseBorder(result, CollapsedBorderValue(&parent()->style()->borderLeft(), parent()->style()->visitedDependentColor(left), BROW));
if (!result.exists())
return result;
// (4) Our row group's left border.
- result = compareBorders(result, CollapsedBorderValue(&section()->style()->borderLeft(), section()->style()->visitedDependentColor(left), BROWGROUP));
+ result = chooseBorder(result, CollapsedBorderValue(&section()->style()->borderLeft(), section()->style()->visitedDependentColor(left), BROWGROUP));
if (!result.exists())
return result;
}
@@ -375,11 +394,11 @@ CollapsedBorderValue RenderTableCell::collapsedLeftBorder(bool rtl) const
bool endColEdge;
RenderTableCol* colElt = tableElt->colElement(col() + (rtl ? colSpan() - 1 : 0), &startColEdge, &endColEdge);
if (colElt && (!rtl ? startColEdge : endColEdge)) {
- result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderLeft(), colElt->style()->visitedDependentColor(left), BCOL));
+ result = chooseBorder(result, CollapsedBorderValue(&colElt->style()->borderLeft(), colElt->style()->visitedDependentColor(left), BCOL));
if (!result.exists())
return result;
if (colElt->parent()->isTableCol() && (!rtl ? !colElt->previousSibling() : !colElt->nextSibling())) {
- result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderLeft(), colElt->parent()->style()->visitedDependentColor(left), BCOLGROUP));
+ result = chooseBorder(result, CollapsedBorderValue(&colElt->parent()->style()->borderLeft(), colElt->parent()->style()->visitedDependentColor(left), BCOLGROUP));
if (!result.exists())
return result;
}
@@ -390,13 +409,13 @@ CollapsedBorderValue RenderTableCell::collapsedLeftBorder(bool rtl) const
colElt = tableElt->colElement(col() + (rtl ? colSpan() : -1), &startColEdge, &endColEdge);
if (colElt && (!rtl ? endColEdge : startColEdge)) {
CollapsedBorderValue rightBorder = CollapsedBorderValue(&colElt->style()->borderRight(), colElt->style()->visitedDependentColor(right), BCOL);
- result = rtl ? compareBorders(result, rightBorder) : compareBorders(rightBorder, result);
+ result = rtl ? chooseBorder(result, rightBorder) : chooseBorder(rightBorder, result);
if (!result.exists())
return result;
}
} else {
// (7) The table's left border.
- result = compareBorders(result, CollapsedBorderValue(&tableElt->style()->borderLeft(), tableElt->style()->visitedDependentColor(left), BTABLE));
+ result = chooseBorder(result, CollapsedBorderValue(&tableElt->style()->borderLeft(), tableElt->style()->visitedDependentColor(left), BTABLE));
if (!result.exists())
return result;
}
@@ -426,18 +445,18 @@ CollapsedBorderValue RenderTableCell::collapsedRightBorder(bool rtl) const
RenderTableCell* nextCell = rtl ? tableElt->cellBefore(this) : tableElt->cellAfter(this);
if (nextCell && nextCell->style()) {
CollapsedBorderValue leftBorder = CollapsedBorderValue(&nextCell->style()->borderLeft(), nextCell->style()->visitedDependentColor(left), BCELL);
- result = rtl ? compareBorders(leftBorder, result) : compareBorders(result, leftBorder);
+ result = rtl ? chooseBorder(leftBorder, result) : chooseBorder(result, leftBorder);
if (!result.exists())
return result;
}
} else {
// (3) Our row's right border.
- result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderRight(), parent()->style()->visitedDependentColor(right), BROW));
+ result = chooseBorder(result, CollapsedBorderValue(&parent()->style()->borderRight(), parent()->style()->visitedDependentColor(right), BROW));
if (!result.exists())
return result;
// (4) Our row group's right border.
- result = compareBorders(result, CollapsedBorderValue(&section()->style()->borderRight(), section()->style()->visitedDependentColor(right), BROWGROUP));
+ result = chooseBorder(result, CollapsedBorderValue(&section()->style()->borderRight(), section()->style()->visitedDependentColor(right), BROWGROUP));
if (!result.exists())
return result;
}
@@ -447,11 +466,11 @@ CollapsedBorderValue RenderTableCell::collapsedRightBorder(bool rtl) const
bool endColEdge;
RenderTableCol* colElt = tableElt->colElement(col() + (rtl ? 0 : colSpan() - 1), &startColEdge, &endColEdge);
if (colElt && (!rtl ? endColEdge : startColEdge)) {
- result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderRight(), colElt->style()->visitedDependentColor(right), BCOL));
+ result = chooseBorder(result, CollapsedBorderValue(&colElt->style()->borderRight(), colElt->style()->visitedDependentColor(right), BCOL));
if (!result.exists())
return result;
if (colElt->parent()->isTableCol() && (!rtl ? !colElt->nextSibling() : !colElt->previousSibling())) {
- result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderRight(), colElt->parent()->style()->visitedDependentColor(right), BCOLGROUP));
+ result = chooseBorder(result, CollapsedBorderValue(&colElt->parent()->style()->borderRight(), colElt->parent()->style()->visitedDependentColor(right), BCOLGROUP));
if (!result.exists())
return result;
}
@@ -462,13 +481,13 @@ CollapsedBorderValue RenderTableCell::collapsedRightBorder(bool rtl) const
colElt = tableElt->colElement(col() + (rtl ? -1 : colSpan()), &startColEdge, &endColEdge);
if (colElt && (!rtl ? startColEdge : endColEdge)) {
CollapsedBorderValue leftBorder = CollapsedBorderValue(&colElt->style()->borderLeft(), colElt->style()->visitedDependentColor(left), BCOL);
- result = rtl ? compareBorders(leftBorder, result) : compareBorders(result, leftBorder);
+ result = rtl ? chooseBorder(leftBorder, result) : chooseBorder(result, leftBorder);
if (!result.exists())
return result;
}
} else {
// (7) The table's right border.
- result = compareBorders(result, CollapsedBorderValue(&tableElt->style()->borderRight(), tableElt->style()->visitedDependentColor(right), BTABLE));
+ result = chooseBorder(result, CollapsedBorderValue(&tableElt->style()->borderRight(), tableElt->style()->visitedDependentColor(right), BTABLE));
if (!result.exists())
return result;
}
@@ -487,13 +506,13 @@ CollapsedBorderValue RenderTableCell::collapsedTopBorder() const
RenderTableCell* prevCell = table()->cellAbove(this);
if (prevCell) {
// (2) A previous cell's bottom border.
- result = compareBorders(CollapsedBorderValue(&prevCell->style()->borderBottom(), prevCell->style()->visitedDependentColor(bottom), BCELL), result);
+ result = chooseBorder(CollapsedBorderValue(&prevCell->style()->borderBottom(), prevCell->style()->visitedDependentColor(bottom), BCELL), result);
if (!result.exists())
return result;
}
// (3) Our row's top border.
- result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderTop(), parent()->style()->visitedDependentColor(top), BROW));
+ result = chooseBorder(result, CollapsedBorderValue(&parent()->style()->borderTop(), parent()->style()->visitedDependentColor(top), BROW));
if (!result.exists())
return result;
@@ -506,7 +525,7 @@ CollapsedBorderValue RenderTableCell::collapsedTopBorder() const
prevRow = prevCell->section()->lastChild();
if (prevRow) {
- result = compareBorders(CollapsedBorderValue(&prevRow->style()->borderBottom(), prevRow->style()->visitedDependentColor(bottom), BROW), result);
+ result = chooseBorder(CollapsedBorderValue(&prevRow->style()->borderBottom(), prevRow->style()->visitedDependentColor(bottom), BROW), result);
if (!result.exists())
return result;
}
@@ -516,14 +535,14 @@ CollapsedBorderValue RenderTableCell::collapsedTopBorder() const
RenderTableSection* currSection = section();
if (!row()) {
// (5) Our row group's top border.
- result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderTop(), currSection->style()->visitedDependentColor(top), BROWGROUP));
+ result = chooseBorder(result, CollapsedBorderValue(&currSection->style()->borderTop(), currSection->style()->visitedDependentColor(top), BROWGROUP));
if (!result.exists())
return result;
// (6) Previous row group's bottom border.
currSection = table()->sectionAbove(currSection);
if (currSection) {
- result = compareBorders(CollapsedBorderValue(&currSection->style()->borderBottom(), currSection->style()->visitedDependentColor(bottom), BROWGROUP), result);
+ result = chooseBorder(CollapsedBorderValue(&currSection->style()->borderBottom(), currSection->style()->visitedDependentColor(bottom), BROWGROUP), result);
if (!result.exists())
return result;
}
@@ -533,11 +552,11 @@ CollapsedBorderValue RenderTableCell::collapsedTopBorder() const
// (8) Our column and column group's top borders.
RenderTableCol* colElt = table()->colElement(col());
if (colElt) {
- result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderTop(), colElt->style()->visitedDependentColor(top), BCOL));
+ result = chooseBorder(result, CollapsedBorderValue(&colElt->style()->borderTop(), colElt->style()->visitedDependentColor(top), BCOL));
if (!result.exists())
return result;
if (colElt->parent()->isTableCol()) {
- result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderTop(), colElt->parent()->style()->visitedDependentColor(top), BCOLGROUP));
+ result = chooseBorder(result, CollapsedBorderValue(&colElt->parent()->style()->borderTop(), colElt->parent()->style()->visitedDependentColor(top), BCOLGROUP));
if (!result.exists())
return result;
}
@@ -545,7 +564,7 @@ CollapsedBorderValue RenderTableCell::collapsedTopBorder() const
// (9) The table's top border.
RenderTable* enclosingTable = table();
- result = compareBorders(result, CollapsedBorderValue(&enclosingTable->style()->borderTop(), enclosingTable->style()->visitedDependentColor(top), BTABLE));
+ result = chooseBorder(result, CollapsedBorderValue(&enclosingTable->style()->borderTop(), enclosingTable->style()->visitedDependentColor(top), BTABLE));
if (!result.exists())
return result;
}
@@ -564,19 +583,19 @@ CollapsedBorderValue RenderTableCell::collapsedBottomBorder() const
RenderTableCell* nextCell = table()->cellBelow(this);
if (nextCell) {
// (2) A following cell's top border.
- result = compareBorders(result, CollapsedBorderValue(&nextCell->style()->borderTop(), nextCell->style()->visitedDependentColor(top), BCELL));
+ result = chooseBorder(result, CollapsedBorderValue(&nextCell->style()->borderTop(), nextCell->style()->visitedDependentColor(top), BCELL));
if (!result.exists())
return result;
}
// (3) Our row's bottom border. (FIXME: Deal with rowspan!)
- result = compareBorders(result, CollapsedBorderValue(&parent()->style()->borderBottom(), parent()->style()->visitedDependentColor(bottom), BROW));
+ result = chooseBorder(result, CollapsedBorderValue(&parent()->style()->borderBottom(), parent()->style()->visitedDependentColor(bottom), BROW));
if (!result.exists())
return result;
// (4) The next row's top border.
if (nextCell) {
- result = compareBorders(result, CollapsedBorderValue(&nextCell->parent()->style()->borderTop(), nextCell->parent()->style()->visitedDependentColor(top), BROW));
+ result = chooseBorder(result, CollapsedBorderValue(&nextCell->parent()->style()->borderTop(), nextCell->parent()->style()->visitedDependentColor(top), BROW));
if (!result.exists())
return result;
}
@@ -585,14 +604,14 @@ CollapsedBorderValue RenderTableCell::collapsedBottomBorder() const
RenderTableSection* currSection = section();
if (row() + rowSpan() >= currSection->numRows()) {
// (5) Our row group's bottom border.
- result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderBottom(), currSection->style()->visitedDependentColor(bottom), BROWGROUP));
+ result = chooseBorder(result, CollapsedBorderValue(&currSection->style()->borderBottom(), currSection->style()->visitedDependentColor(bottom), BROWGROUP));
if (!result.exists())
return result;
// (6) Following row group's top border.
currSection = table()->sectionBelow(currSection);
if (currSection) {
- result = compareBorders(result, CollapsedBorderValue(&currSection->style()->borderTop(), currSection->style()->visitedDependentColor(top), BROWGROUP));
+ result = chooseBorder(result, CollapsedBorderValue(&currSection->style()->borderTop(), currSection->style()->visitedDependentColor(top), BROWGROUP));
if (!result.exists())
return result;
}
@@ -602,10 +621,10 @@ CollapsedBorderValue RenderTableCell::collapsedBottomBorder() const
// (8) Our column and column group's bottom borders.
RenderTableCol* colElt = table()->colElement(col());
if (colElt) {
- result = compareBorders(result, CollapsedBorderValue(&colElt->style()->borderBottom(), colElt->style()->visitedDependentColor(bottom), BCOL));
+ result = chooseBorder(result, CollapsedBorderValue(&colElt->style()->borderBottom(), colElt->style()->visitedDependentColor(bottom), BCOL));
if (!result.exists()) return result;
if (colElt->parent()->isTableCol()) {
- result = compareBorders(result, CollapsedBorderValue(&colElt->parent()->style()->borderBottom(), colElt->parent()->style()->visitedDependentColor(bottom), BCOLGROUP));
+ result = chooseBorder(result, CollapsedBorderValue(&colElt->parent()->style()->borderBottom(), colElt->parent()->style()->visitedDependentColor(bottom), BCOLGROUP));
if (!result.exists())
return result;
}
@@ -613,7 +632,7 @@ CollapsedBorderValue RenderTableCell::collapsedBottomBorder() const
// (9) The table's bottom border.
RenderTable* enclosingTable = table();
- result = compareBorders(result, CollapsedBorderValue(&enclosingTable->style()->borderBottom(), enclosingTable->style()->visitedDependentColor(bottom), BTABLE));
+ result = chooseBorder(result, CollapsedBorderValue(&enclosingTable->style()->borderBottom(), enclosingTable->style()->visitedDependentColor(bottom), BTABLE));
if (!result.exists())
return result;
}
@@ -776,6 +795,7 @@ static int compareBorderStylesForQSort(const void* pa, const void* pb)
const CollapsedBorderValue* b = static_cast<const CollapsedBorderValue*>(pb);
if (*a == *b)
return 0;
+<<<<<<< HEAD
CollapsedBorderValue borderWithHigherPrecedence = compareBorders(*a, *b);
#ifdef ANDROID_FIX
if (*a == borderWithHigherPrecedence) {
@@ -793,6 +813,9 @@ static int compareBorderStylesForQSort(const void* pa, const void* pb)
return 1;
#endif
return -1;
+=======
+ return compareBorders(*a, *b);
+>>>>>>> webkit.org at r67908
}
void RenderTableCell::sortBorderStyles(CollapsedBorderStyles& borderStyles)
diff --git a/WebCore/rendering/RenderTableRow.cpp b/WebCore/rendering/RenderTableRow.cpp
index a11a14b..0a8bfde 100644
--- a/WebCore/rendering/RenderTableRow.cpp
+++ b/WebCore/rendering/RenderTableRow.cpp
@@ -117,9 +117,14 @@ void RenderTableRow::layout()
// Table rows do not add translation.
LayoutStateMaintainer statePusher(view(), this, IntSize());
+ bool paginated = view()->layoutState()->isPaginated();
+
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
if (child->isTableCell()) {
RenderTableCell* cell = toRenderTableCell(child);
+ if (!cell->needsLayout() && paginated && view()->layoutState()->m_pageHeight && view()->layoutState()->pageY(cell->y()) != cell->pageY())
+ cell->setChildNeedsLayout(true, false);
+
if (child->needsLayout()) {
cell->calcVerticalMargins();
cell->layout();
diff --git a/WebCore/rendering/RenderTableSection.cpp b/WebCore/rendering/RenderTableSection.cpp
index a9052ce..9e59109 100644
--- a/WebCore/rendering/RenderTableSection.cpp
+++ b/WebCore/rendering/RenderTableSection.cpp
@@ -689,26 +689,36 @@ int RenderTableSection::layoutRows(int toAdd)
int be = rHeight - heightWithoutIntrinsicPadding - te;
cell->setIntrinsicPaddingTop(te);
cell->setIntrinsicPaddingBottom(be);
- if (te != oldTe || be != oldBe) {
- cell->setNeedsLayout(true, false);
- cell->layoutIfNeeded();
- }
-
- if ((te != oldTe || be > oldBe) && !table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout())
- cell->repaint();
IntRect oldCellRect(cell->x(), cell->y() , cell->width(), cell->height());
-
+
if (style()->direction() == RTL)
cell->setLocation(table()->columnPositions()[nEffCols] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + hspacing, m_rowPos[rindx]);
else
cell->setLocation(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]);
+ view()->addLayoutDelta(IntSize(oldCellRect.x() - cell->x(), oldCellRect.y() - cell->y()));
- // If the cell moved, we have to repaint it as well as any floating/positioned
- // descendants. An exception is if we need a layout. In this case, we know we're going to
- // repaint ourselves (and the cell) anyway.
- if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout())
- cell->repaintDuringLayoutIfMoved(oldCellRect);
+ if (te != oldTe || be != oldBe)
+ cell->setNeedsLayout(true, false);
+
+ if (!cell->needsLayout() && view()->layoutState()->m_pageHeight && view()->layoutState()->pageY(cell->y()) != cell->pageY())
+ cell->setChildNeedsLayout(true, false);
+
+ cell->layoutIfNeeded();
+
+ if (view()->layoutState()->m_pageHeight && cell->height() != rHeight)
+ cell->setHeight(rHeight); // FIXME: Pagination might have made us change size. For now just shrink or grow the cell to fit without doing a relayout.
+
+ IntSize childOffset(cell->x() - oldCellRect.x(), cell->y() - oldCellRect.y());
+ if (childOffset.width() || childOffset.height()) {
+ view()->addLayoutDelta(childOffset);
+
+ // If the child moved, we have to repaint it as well as any floating/positioned
+ // descendants. An exception is if we need a layout. In this case, we know we're going to
+ // repaint ourselves (and the child) anyway.
+ if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout())
+ cell->repaintDuringLayoutIfMoved(oldCellRect);
+ }
}
}
diff --git a/WebCore/rendering/RenderText.cpp b/WebCore/rendering/RenderText.cpp
index da152b0..d786e6a 100644
--- a/WebCore/rendering/RenderText.cpp
+++ b/WebCore/rendering/RenderText.cpp
@@ -310,10 +310,46 @@ void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, u
}
}
+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 = max<int>(startPos - box->start(), 0);
+ int ellipsisEndPosition = 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(0, 0);
+ }
+
+ return IntRect();
+}
+
+void RenderText::absoluteQuads(Vector<FloatQuad>& quads, ClippingOption option)
+{
+ for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
+ IntRect boundaries = box->calculateBoundaries();
+
+ // Shorten the width of this text box if it ends in an ellipsis.
+ IntRect ellipsisRect = (option == ClipToEllipsis) ? ellipsisRectForBox(box, 0, textLength()) : IntRect();
+ if (!ellipsisRect.isEmpty())
+ boundaries.setWidth(ellipsisRect.right() - boundaries.x());
+ quads.append(localToAbsoluteQuad(FloatRect(boundaries)));
+ }
+}
+
void RenderText::absoluteQuads(Vector<FloatQuad>& quads)
{
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- quads.append(localToAbsoluteQuad(FloatRect(box->calculateBoundaries())));
+ absoluteQuads(quads, NoClipping);
}
void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool useSelectionHeight)
@@ -1270,7 +1306,7 @@ IntRect RenderText::selectionRectForRepaint(RenderBoxModelObject* repaintContain
if (selectionState() == SelectionNone)
return IntRect();
- RenderBlock* cb = containingBlock();
+ RenderBlock* cb = containingBlock();
if (!cb)
return IntRect();
@@ -1295,21 +1331,7 @@ IntRect RenderText::selectionRectForRepaint(RenderBoxModelObject* repaintContain
IntRect rect;
for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
rect.unite(box->selectionRect(0, 0, startPos, endPos));
-
- // Check if there are ellipsis which fall within the selection.
- unsigned short truncation = box->truncation();
- if (truncation != cNoTruncation) {
- if (EllipsisBox* ellipsis = box->root()->ellipsisBox()) {
- int ePos = min<int>(endPos - box->start(), box->len());
- int sPos = max<int>(startPos - box->start(), 0);
- // 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 (ePos >= truncation && sPos <= truncation)
- rect.unite(ellipsis->selectionRect(0, 0));
- }
- }
+ rect.unite(ellipsisRectForBox(box, startPos, endPos));
}
if (clipToVisibleContent)
diff --git a/WebCore/rendering/RenderText.h b/WebCore/rendering/RenderText.h
index f46f053..6ab73f6 100644
--- a/WebCore/rendering/RenderText.h
+++ b/WebCore/rendering/RenderText.h
@@ -62,6 +62,9 @@ public:
virtual void absoluteQuads(Vector<FloatQuad>&);
void absoluteQuadsForRange(Vector<FloatQuad>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
+ enum ClippingOption { NoClipping, ClipToEllipsis };
+ void absoluteQuads(Vector<FloatQuad>&, ClippingOption option = NoClipping);
+
virtual VisiblePosition positionForPoint(const IntPoint&);
const UChar* characters() const { return m_text.characters(); }
@@ -83,7 +86,7 @@ public:
int& beginMaxW, int& endMaxW,
int& minW, int& maxW, bool& stripFrontSpaces);
- IntRect linesBoundingBox() const;
+ virtual IntRect linesBoundingBox() const;
IntPoint firstRunOrigin() const;
int firstRunX() const;
diff --git a/WebCore/rendering/RenderTextFragment.h b/WebCore/rendering/RenderTextFragment.h
index e351436..e023042 100644
--- a/WebCore/rendering/RenderTextFragment.h
+++ b/WebCore/rendering/RenderTextFragment.h
@@ -59,6 +59,21 @@ private:
RenderObject* m_firstLetter;
};
+inline RenderTextFragment* toRenderTextFragment(RenderObject* object)
+{
+ ASSERT(!object || toRenderText(object)->isTextFragment());
+ return static_cast<RenderTextFragment*>(object);
+}
+
+inline const RenderTextFragment* toRenderTextFragment(const RenderObject* object)
+{
+ ASSERT(!object || toRenderText(object)->isTextFragment());
+ return static_cast<const RenderTextFragment*>(object);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toRenderTextFragment(const RenderTextFragment*);
+
} // namespace WebCore
#endif // RenderTextFragment_h
diff --git a/WebCore/rendering/RenderThemeWin.cpp b/WebCore/rendering/RenderThemeWin.cpp
index 8a33173..b4fb8eb 100644
--- a/WebCore/rendering/RenderThemeWin.cpp
+++ b/WebCore/rendering/RenderThemeWin.cpp
@@ -749,15 +749,16 @@ const int sliderThumbHeight = 15;
void RenderThemeWin::adjustSliderThumbSize(RenderObject* o) const
{
- if (o->style()->appearance() == SliderThumbVerticalPart) {
+ ControlPart part = o->style()->appearance();
+ if (part == SliderThumbVerticalPart) {
o->style()->setWidth(Length(sliderThumbHeight, Fixed));
o->style()->setHeight(Length(sliderThumbWidth, Fixed));
- } else if (o->style()->appearance() == SliderThumbHorizontalPart) {
+ } else if (part == SliderThumbHorizontalPart) {
o->style()->setWidth(Length(sliderThumbWidth, Fixed));
o->style()->setHeight(Length(sliderThumbHeight, Fixed));
}
#if ENABLE(VIDEO)
- else if (o->style()->appearance() == MediaSliderThumbPart)
+ else if (part == MediaSliderThumbPart || part == MediaVolumeSliderThumbPart)
RenderMediaControls::adjustMediaSliderThumbSize(o);
#endif
}
@@ -937,6 +938,11 @@ Color RenderThemeWin::systemColor(int cssValueId) const
#if ENABLE(VIDEO)
+String RenderThemeWin::extraMediaControlsStyleSheet()
+{
+ return String(mediaControlsQuickTimeUserAgentStyleSheet, sizeof(mediaControlsQuickTimeUserAgentStyleSheet));
+}
+
bool RenderThemeWin::shouldRenderMediaControlPart(ControlPart part, Element* element)
{
if (part == MediaToggleClosedCaptionsButtonPart) {
@@ -968,6 +974,11 @@ bool RenderThemeWin::paintMediaPlayButton(RenderObject* o, const PaintInfo& pain
return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, o, paintInfo, r);
}
+bool RenderThemeWin::paintMediaRewindButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ return RenderMediaControls::paintMediaControlsPart(MediaRewindButton, o, paintInfo, r);
+}
+
bool RenderThemeWin::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
return RenderMediaControls::paintMediaControlsPart(MediaSeekBackButton, o, paintInfo, r);
@@ -993,6 +1004,32 @@ bool RenderThemeWin::paintMediaToggleClosedCaptionsButton(RenderObject* o, const
return RenderMediaControls::paintMediaControlsPart(MediaShowClosedCaptionsButton, o, paintInfo, r);
}
+bool RenderThemeWin::paintMediaControlsBackground(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ return RenderMediaControls::paintMediaControlsPart(MediaTimelineContainer, o, paintInfo, r);
+}
+
+bool RenderThemeWin::paintMediaVolumeSliderContainer(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ return RenderMediaControls::paintMediaControlsPart(MediaVolumeSliderContainer, o, paintInfo, r);
+}
+
+bool RenderThemeWin::paintMediaVolumeSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ return RenderMediaControls::paintMediaControlsPart(MediaVolumeSlider, o, paintInfo, r);
+}
+
+bool RenderThemeWin::paintMediaVolumeSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ return RenderMediaControls::paintMediaControlsPart(MediaVolumeSliderThumb, o, paintInfo, r);
+}
+
+IntPoint RenderThemeWin::volumeSliderOffsetFromMuteButton(Node* muteButton, const IntSize& size) const
+{
+ return RenderMediaControls::volumeSliderOffsetFromMuteButton(muteButton, size);
+}
+
+
#endif
}
diff --git a/WebCore/rendering/RenderThemeWin.h b/WebCore/rendering/RenderThemeWin.h
index 0147900..1efb117 100644
--- a/WebCore/rendering/RenderThemeWin.h
+++ b/WebCore/rendering/RenderThemeWin.h
@@ -120,15 +120,22 @@ public:
virtual bool supportsFocusRing(const RenderStyle*) const;
#if ENABLE(VIDEO)
+ virtual String extraMediaControlsStyleSheet();
virtual bool shouldRenderMediaControlPart(ControlPart, Element*);
+ virtual bool paintMediaControlsBackground(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&);
- virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaRewindButton(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaSeekBackButton(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaSeekForwardButton(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual IntPoint volumeSliderOffsetFromMuteButton(Node*, const IntSize&) const;
#endif
private:
diff --git a/WebCore/rendering/RenderThemeWince.cpp b/WebCore/rendering/RenderThemeWinCE.cpp
index 117601b..66cda11 100644
--- a/WebCore/rendering/RenderThemeWince.cpp
+++ b/WebCore/rendering/RenderThemeWinCE.cpp
@@ -22,7 +22,7 @@
*/
#include "config.h"
-#include "RenderThemeWince.h"
+#include "RenderThemeWinCE.h"
#include "CSSStyleSheet.h"
#include "CSSValueKeywords.h"
@@ -83,49 +83,49 @@ namespace WebCore {
static const int dropDownButtonWidth = 17;
static const int trackWidth = 4;
-PassRefPtr<RenderTheme> RenderThemeWince::create()
+PassRefPtr<RenderTheme> RenderThemeWinCE::create()
{
- return adoptRef(new RenderThemeWince);
+ return adoptRef(new RenderThemeWinCE);
}
PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
{
- static RenderTheme* winceTheme = RenderThemeWince::create().releaseRef();
+ static RenderTheme* winceTheme = RenderThemeWinCE::create().releaseRef();
return winceTheme;
}
-RenderThemeWince::RenderThemeWince()
+RenderThemeWinCE::RenderThemeWinCE()
{
}
-RenderThemeWince::~RenderThemeWince()
+RenderThemeWinCE::~RenderThemeWinCE()
{
}
-Color RenderThemeWince::platformActiveSelectionBackgroundColor() const
+Color RenderThemeWinCE::platformActiveSelectionBackgroundColor() const
{
COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
}
-Color RenderThemeWince::platformInactiveSelectionBackgroundColor() const
+Color RenderThemeWinCE::platformInactiveSelectionBackgroundColor() const
{
COLORREF color = GetSysColor(COLOR_GRAYTEXT);
return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
}
-Color RenderThemeWince::platformActiveSelectionForegroundColor() const
+Color RenderThemeWinCE::platformActiveSelectionForegroundColor() const
{
COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
}
-Color RenderThemeWince::platformInactiveSelectionForegroundColor() const
+Color RenderThemeWinCE::platformInactiveSelectionForegroundColor() const
{
return Color::white;
}
-bool RenderThemeWince::supportsFocus(ControlPart appearance) const
+bool RenderThemeWinCE::supportsFocus(ControlPart appearance) const
{
switch (appearance) {
case PushButtonPart:
@@ -140,12 +140,12 @@ bool RenderThemeWince::supportsFocus(ControlPart appearance) const
return false;
}
-bool RenderThemeWince::supportsFocusRing(const RenderStyle *style) const
+bool RenderThemeWinCE::supportsFocusRing(const RenderStyle *style) const
{
return supportsFocus(style->appearance());
}
-unsigned RenderThemeWince::determineClassicState(RenderObject* o)
+unsigned RenderThemeWinCE::determineClassicState(RenderObject* o)
{
unsigned result = 0;
if (!isEnabled(o) || isReadOnlyControl(o))
@@ -158,7 +158,7 @@ unsigned RenderThemeWince::determineClassicState(RenderObject* o)
return result;
}
-ThemeData RenderThemeWince::getThemeData(RenderObject* o)
+ThemeData RenderThemeWinCE::getThemeData(RenderObject* o)
{
ThemeData result;
switch (o->style()->appearance()) {
@@ -188,7 +188,7 @@ ThemeData RenderThemeWince::getThemeData(RenderObject* o)
return result;
}
-bool RenderThemeWince::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
+bool RenderThemeWinCE::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
// Get the correct theme data for a button
ThemeData themeData = getThemeData(o);
@@ -207,7 +207,7 @@ bool RenderThemeWince::paintButton(RenderObject* o, const PaintInfo& i, const In
return false;
}
-void RenderThemeWince::setCheckboxSize(RenderStyle* style) const
+void RenderThemeWinCE::setCheckboxSize(RenderStyle* style) const
{
// If the width and height are both specified, then we have nothing to do.
if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
@@ -223,7 +223,7 @@ void RenderThemeWince::setCheckboxSize(RenderStyle* style) const
style->setHeight(Length(13, Fixed));
}
-bool RenderThemeWince::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r)
+bool RenderThemeWinCE::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
// Get the correct theme data for a textfield
ThemeData themeData = getThemeData(o);
@@ -234,20 +234,20 @@ bool RenderThemeWince::paintTextField(RenderObject* o, const PaintInfo& i, const
return false;
}
-void RenderThemeWince::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeWinCE::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
style->resetBorder();
adjustMenuListButtonStyle(selector, style, e);
}
-bool RenderThemeWince::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r)
+bool RenderThemeWinCE::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
paintTextField(o, i, r);
paintMenuListButton(o, i, r);
return true;
}
-bool RenderThemeWince::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
+bool RenderThemeWinCE::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
IntRect buttonRect(r.right() - dropDownButtonWidth - 1, r.y(), dropDownButtonWidth, r.height());
buttonRect.inflateY(-1);
@@ -255,28 +255,28 @@ bool RenderThemeWince::paintMenuListButton(RenderObject* o, const PaintInfo& i,
return true;
}
-void RenderThemeWince::systemFont(int propId, FontDescription& fontDescription) const
+void RenderThemeWinCE::systemFont(int propId, FontDescription& fontDescription) const
{
notImplemented();
}
-void RenderThemeWince::themeChanged()
+void RenderThemeWinCE::themeChanged()
{
}
-String RenderThemeWince::extraDefaultStyleSheet()
+String RenderThemeWinCE::extraDefaultStyleSheet()
{
notImplemented();
return String();
}
-String RenderThemeWince::extraQuirksStyleSheet()
+String RenderThemeWinCE::extraQuirksStyleSheet()
{
notImplemented();
return String();
}
-bool RenderThemeWince::supportsHover(const RenderStyle*) const
+bool RenderThemeWinCE::supportsHover(const RenderStyle*) const
{
return false;
}
@@ -317,7 +317,7 @@ static int cssValueIdToSysColorIndex(int cssValueId)
}
}
-Color RenderThemeWince::systemColor(int cssValueId) const
+Color RenderThemeWinCE::systemColor(int cssValueId) const
{
int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
if (sysColorIndex == -1)
@@ -330,7 +330,7 @@ Color RenderThemeWince::systemColor(int cssValueId) const
const int sliderThumbWidth = 7;
const int sliderThumbHeight = 15;
-void RenderThemeWince::adjustSliderThumbSize(RenderObject* o) const
+void RenderThemeWinCE::adjustSliderThumbSize(RenderObject* o) const
{
if (o->style()->appearance() == SliderThumbVerticalPart) {
o->style()->setWidth(Length(sliderThumbHeight, Fixed));
@@ -342,7 +342,7 @@ void RenderThemeWince::adjustSliderThumbSize(RenderObject* o) const
}
#if 0
-void RenderThemeWince::adjustButtonInnerStyle(RenderStyle* style) const
+void RenderThemeWinCE::adjustButtonInnerStyle(RenderStyle* style) const
{
// This inner padding matches Firefox.
style->setPaddingTop(Length(1, Fixed));
@@ -351,7 +351,7 @@ void RenderThemeWince::adjustButtonInnerStyle(RenderStyle* style) const
style->setPaddingLeft(Length(3, Fixed));
}
-void RenderThemeWince::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeWinCE::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
// Override padding size to match AppKit text positioning.
const int padding = 1;
@@ -362,12 +362,12 @@ void RenderThemeWince::adjustSearchFieldStyle(CSSStyleSelector* selector, Render
}
#endif
-bool RenderThemeWince::paintSearchField(RenderObject* o, const PaintInfo& i, const IntRect& r)
+bool RenderThemeWinCE::paintSearchField(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
return paintTextField(o, i, r);
}
-bool RenderThemeWince::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeWinCE::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
Color buttonColor = (o->node() && o->node()->active()) ? Color(138, 138, 138) : Color(186, 186, 186);
@@ -391,47 +391,47 @@ bool RenderThemeWince::paintSearchFieldCancelButton(RenderObject* o, const Paint
return false;
}
-void RenderThemeWince::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeWinCE::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
IntSize cancelSize(13, 11);
style->setWidth(Length(cancelSize.width(), Fixed));
style->setHeight(Length(cancelSize.height(), Fixed));
}
-void RenderThemeWince::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeWinCE::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
IntSize emptySize(1, 11);
style->setWidth(Length(emptySize.width(), Fixed));
style->setHeight(Length(emptySize.height(), Fixed));
}
-void RenderThemeWince::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeWinCE::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
IntSize magnifierSize(15, 11);
style->setWidth(Length(magnifierSize.width(), Fixed));
style->setHeight(Length(magnifierSize.height(), Fixed));
}
-bool RenderThemeWince::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeWinCE::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
notImplemented();
return false;
}
-void RenderThemeWince::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeWinCE::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
IntSize magnifierSize(15, 11);
style->setWidth(Length(magnifierSize.width(), Fixed));
style->setHeight(Length(magnifierSize.height(), Fixed));
}
-bool RenderThemeWince::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeWinCE::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
paintSearchFieldResultsDecoration(o, paintInfo, r);
return false;
}
-void RenderThemeWince::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeWinCE::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
// These are the paddings needed to place the text correctly in the <select> box
const int dropDownBoxPaddingTop = 2;
@@ -485,7 +485,7 @@ static HTMLMediaElement* mediaElementParent(Node* node)
}
#endif
-bool RenderThemeWince::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r)
+bool RenderThemeWinCE::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
bool rc = RenderTheme::paintSliderTrack(o, i, r);
IntPoint left = IntPoint(r.x() + 2, (r.y() + r.bottom()) / 2);
@@ -508,7 +508,7 @@ bool RenderThemeWince::paintSliderTrack(RenderObject* o, const PaintInfo& i, con
return rc;
}
-bool RenderThemeWince::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r)
+bool RenderThemeWinCE::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r)
{
bool rc = RenderTheme::paintSliderThumb(o, i, r);
i.context->save();
@@ -528,7 +528,7 @@ bool RenderThemeWince::paintSliderThumb(RenderObject* o, const PaintInfo& i, con
return rc;
}
-void RenderThemeWince::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+void RenderThemeWinCE::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
const int padding = 1;
style->setPaddingLeft(Length(padding, Fixed));
@@ -539,7 +539,7 @@ void RenderThemeWince::adjustSearchFieldStyle(CSSStyleSelector* selector, Render
#if ENABLE(VIDEO)
-bool RenderThemeWince::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeWinCE::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
bool rc = paintButton(o, paintInfo, r);
FloatRect imRect = r;
@@ -552,7 +552,7 @@ bool RenderThemeWince::paintMediaFullscreenButton(RenderObject* o, const PaintIn
return rc;
}
-bool RenderThemeWince::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeWinCE::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
bool rc = paintButton(o, paintInfo, r);
HTMLMediaElement* mediaElement = mediaElementParent(o->node());
@@ -577,7 +577,7 @@ bool RenderThemeWince::paintMediaMuteButton(RenderObject* o, const PaintInfo& pa
return rc;
}
-bool RenderThemeWince::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeWinCE::paintMediaPlayButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
bool rc = paintButton(o, paintInfo, r);
FloatRect imRect = r;
@@ -601,7 +601,7 @@ bool RenderThemeWince::paintMediaPlayButton(RenderObject* o, const PaintInfo& pa
return rc;
}
-bool RenderThemeWince::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeWinCE::paintMediaSeekBackButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
bool rc = paintButton(o, paintInfo, r);
FloatRect imRect = r;
@@ -617,7 +617,7 @@ bool RenderThemeWince::paintMediaSeekBackButton(RenderObject* o, const PaintInfo
return rc;
}
-bool RenderThemeWince::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeWinCE::paintMediaSeekForwardButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
bool rc = paintButton(o, paintInfo, r);
FloatRect imRect = r;
@@ -633,15 +633,15 @@ bool RenderThemeWince::paintMediaSeekForwardButton(RenderObject* o, const PaintI
return rc;
}
-bool RenderThemeWince::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeWinCE::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
return paintSliderTrack(o, paintInfo, r);
}
-bool RenderThemeWince::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+bool RenderThemeWinCE::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
{
return paintSliderThumb(o, paintInfo, r);
}
#endif
-}
+} // namespace WebCore
diff --git a/WebCore/rendering/RenderThemeWince.h b/WebCore/rendering/RenderThemeWinCE.h
index c1b57d4..14a5b12 100644
--- a/WebCore/rendering/RenderThemeWince.h
+++ b/WebCore/rendering/RenderThemeWinCE.h
@@ -21,8 +21,8 @@
*
*/
-#ifndef RenderThemeWince_h
-#define RenderThemeWince_h
+#ifndef RenderThemeWinCE_h
+#define RenderThemeWinCE_h
#include "RenderTheme.h"
@@ -45,10 +45,10 @@ namespace WebCore {
unsigned m_classicState;
};
- class RenderThemeWince : public RenderTheme {
+ class RenderThemeWinCE : public RenderTheme {
public:
static PassRefPtr<RenderTheme> create();
- ~RenderThemeWince();
+ ~RenderThemeWinCE();
virtual String extraDefaultStyleSheet();
virtual String extraQuirksStyleSheet();
@@ -129,7 +129,7 @@ namespace WebCore {
#endif
private:
- RenderThemeWince();
+ RenderThemeWinCE();
unsigned determineClassicState(RenderObject*);
bool supportsFocus(ControlPart) const;
@@ -139,4 +139,4 @@ namespace WebCore {
};
-#endif
+#endif // RenderThemeWinCE_h
diff --git a/WebCore/rendering/RenderVideo.cpp b/WebCore/rendering/RenderVideo.cpp
index 3f4e2bf..3dfee7b 100644
--- a/WebCore/rendering/RenderVideo.cpp
+++ b/WebCore/rendering/RenderVideo.cpp
@@ -80,6 +80,7 @@ void RenderVideo::intrinsicSizeChanged()
void RenderVideo::updateIntrinsicSize()
{
IntSize size = calculateIntrinsicSize();
+ size.scale(style()->effectiveZoom());
// Never set the element size to zero when in a media document.
if (size.isEmpty() && node()->ownerDocument() && node()->ownerDocument()->isMediaDocument())
@@ -187,9 +188,6 @@ void RenderVideo::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
MediaPlayer* mediaPlayer = player();
bool displayingPoster = videoElement()->shouldDisplayPosterImage();
- if (displayingPoster && document()->printing() && !view()->printImages())
- return;
-
if (!displayingPoster) {
if (!mediaPlayer)
return;
@@ -250,53 +248,17 @@ void RenderVideo::updatePlayer()
int RenderVideo::calcReplacedWidth(bool includeMaxWidth) const
{
- int width;
- if (isWidthSpecified())
- width = calcReplacedWidthUsing(style()->width());
- else
- width = calcAspectRatioWidth() * style()->effectiveZoom();
-
- int minW = calcReplacedWidthUsing(style()->minWidth());
- int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth());
-
- return max(minW, min(width, maxW));
+ return RenderReplaced::calcReplacedWidth(includeMaxWidth);
}
int RenderVideo::calcReplacedHeight() const
{
- int height;
- if (isHeightSpecified())
- height = calcReplacedHeightUsing(style()->height());
- else
- height = calcAspectRatioHeight() * style()->effectiveZoom();
-
- int minH = calcReplacedHeightUsing(style()->minHeight());
- int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight());
-
- return max(minH, min(height, maxH));
-}
-
-int RenderVideo::calcAspectRatioWidth() const
-{
- int intrinsicWidth = intrinsicSize().width();
- int intrinsicHeight = intrinsicSize().height();
- if (!intrinsicHeight)
- return 0;
- return RenderBox::calcReplacedHeight() * intrinsicWidth / intrinsicHeight;
-}
-
-int RenderVideo::calcAspectRatioHeight() const
-{
- int intrinsicWidth = intrinsicSize().width();
- int intrinsicHeight = intrinsicSize().height();
- if (!intrinsicWidth)
- return 0;
- return RenderBox::calcReplacedWidth() * intrinsicHeight / intrinsicWidth;
+ return RenderReplaced::calcReplacedHeight();
}
int RenderVideo::minimumReplacedHeight() const
{
- return 0;
+ return RenderReplaced::minimumReplacedHeight();
}
#if USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/rendering/RenderVideo.h b/WebCore/rendering/RenderVideo.h
index dd7a531..2c47471 100644
--- a/WebCore/rendering/RenderVideo.h
+++ b/WebCore/rendering/RenderVideo.h
@@ -74,9 +74,6 @@ private:
virtual int calcReplacedHeight() const;
virtual int minimumReplacedHeight() const;
- int calcAspectRatioWidth() const;
- int calcAspectRatioHeight() const;
-
void updatePlayer();
IntSize m_cachedImageSize;
diff --git a/WebCore/rendering/RenderView.cpp b/WebCore/rendering/RenderView.cpp
index eba3468..edee4f6 100644
--- a/WebCore/rendering/RenderView.cpp
+++ b/WebCore/rendering/RenderView.cpp
@@ -52,12 +52,8 @@ RenderView::RenderView(Node* node, FrameView* view)
, m_selectionEnd(0)
, m_selectionStartPos(-1)
, m_selectionEndPos(-1)
- , m_printImages(true)
, m_maximalOutlineSize(0)
- , m_bestTruncatedAt(0)
- , m_truncatorWidth(0)
- , m_minimumColumnHeight(0)
- , m_forcedPageBreak(false)
+ , m_pageHeight(0)
, m_layoutState(0)
, m_layoutStateDisableCount(0)
{
@@ -112,6 +108,9 @@ void RenderView::calcPrefWidths()
void RenderView::layout()
{
+ if (!document()->paginated())
+ setPageHeight(0);
+
if (printing())
m_minPrefWidth = m_maxPrefWidth = width();
@@ -129,6 +128,7 @@ void RenderView::layout()
LayoutState state;
// FIXME: May be better to push a clip and avoid issuing offscreen repaints.
state.m_clipped = false;
+ state.m_pageHeight = m_pageHeight;
m_layoutState = &state;
if (needsLayout())
@@ -138,7 +138,6 @@ void RenderView::layout()
m_overflow.clear();
addLayoutOverflow(IntRect(0, 0, docWidth(), docHeight()));
-
ASSERT(layoutDelta() == IntSize());
ASSERT(m_layoutStateDisableCount == 0);
ASSERT(m_layoutState == &state);
@@ -184,12 +183,6 @@ void RenderView::paint(PaintInfo& paintInfo, int tx, int ty)
{
// If we ever require layout but receive a paint anyway, something has gone horribly wrong.
ASSERT(!needsLayout());
-
- // Cache the print rect because the dirty rect could get changed during painting.
- if (document()->paginated())
- setPrintRect(paintInfo.rect);
- else
- setPrintRect(IntRect());
paintObject(paintInfo, tx, ty);
}
@@ -703,37 +696,12 @@ int RenderView::viewWidth() const
float RenderView::zoomFactor() const
{
- if (!m_frameView->shouldApplyPageZoom())
- return 1;
- return m_frameView->zoomFactor();
-}
-
-// The idea here is to take into account what object is moving the pagination point, and
-// thus choose the best place to chop it.
-void RenderView::setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak)
-{
- // Nobody else can set a page break once we have a forced break.
- if (m_forcedPageBreak)
- return;
-
- // Forced breaks always win over unforced breaks.
- if (forcedBreak) {
- m_forcedPageBreak = true;
- m_bestTruncatedAt = y;
- return;
- }
-
- // Prefer the widest object that tries to move the pagination point
- IntRect boundingBox = forRenderer->borderBoundingBox();
- if (boundingBox.width() > m_truncatorWidth) {
- m_truncatorWidth = boundingBox.width();
- m_bestTruncatedAt = y;
- }
+ Frame* frame = m_frameView->frame();
+ return frame ? frame->pageZoomFactor() : 1;
}
void RenderView::pushLayoutState(RenderObject* root)
{
- ASSERT(!doingFullRepaint());
ASSERT(m_layoutStateDisableCount == 0);
ASSERT(m_layoutState == 0);
@@ -765,6 +733,31 @@ void RenderView::updateHitTestResult(HitTestResult& result, const IntPoint& poin
}
}
+// FIXME: This function is obsolete and only used by embedded WebViews inside AppKit NSViews.
+// Do not add callers of this function!
+// The idea here is to take into account what object is moving the pagination point, and
+// thus choose the best place to chop it.
+void RenderView::setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak)
+{
+ // Nobody else can set a page break once we have a forced break.
+ if (m_legacyPrinting.m_forcedPageBreak)
+ return;
+
+ // Forced breaks always win over unforced breaks.
+ if (forcedBreak) {
+ m_legacyPrinting.m_forcedPageBreak = true;
+ m_legacyPrinting.m_bestTruncatedAt = y;
+ return;
+ }
+
+ // Prefer the widest object that tries to move the pagination point
+ IntRect boundingBox = forRenderer->borderBoundingBox();
+ if (boundingBox.width() > m_legacyPrinting.m_truncatorWidth) {
+ m_legacyPrinting.m_truncatorWidth = boundingBox.width();
+ m_legacyPrinting.m_bestTruncatedAt = y;
+ }
+}
+
#if USE(ACCELERATED_COMPOSITING)
bool RenderView::usesCompositing() const
{
diff --git a/WebCore/rendering/RenderView.h b/WebCore/rendering/RenderView.h
index 8145cac..55aa3b4 100644
--- a/WebCore/rendering/RenderView.h
+++ b/WebCore/rendering/RenderView.h
@@ -77,19 +77,6 @@ public:
void selectionStartEnd(int& startPos, int& endPos) const;
bool printing() const;
- void setPrintImages(bool enable) { m_printImages = enable; }
- bool printImages() const { return m_printImages; }
-
- IntRect printRect() const { return m_printRect; }
- void setPrintRect(const IntRect& r) { m_printRect = r; }
-
- void setTruncatedAt(int y) { m_truncatedAt = y; m_bestTruncatedAt = m_truncatorWidth = 0; m_minimumColumnHeight = 0; m_forcedPageBreak = false; }
- void setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak = false);
- void setMinimumColumnHeight(int height) { m_minimumColumnHeight = height; }
- int bestTruncatedAt() const { return m_bestTruncatedAt; }
- int minimumColumnHeight() const { return m_minimumColumnHeight; }
-
- int truncatedAt() const { return m_truncatedAt; }
virtual void absoluteRects(Vector<IntRect>&, int tx, int ty);
virtual void absoluteQuads(Vector<FloatQuad>&);
@@ -125,24 +112,9 @@ public:
bool doingFullRepaint() const { return m_frameView->needsFullRepaint(); }
- void pushLayoutState(RenderBox* renderer, const IntSize& offset)
- {
- if (doingFullRepaint())
- return;
- // We push LayoutState even if layoutState is disabled because it stores layoutDelta too.
- m_layoutState = new (renderArena()) LayoutState(m_layoutState, renderer, offset);
- }
-
+ // Subtree push/pop
void pushLayoutState(RenderObject*);
-
- void popLayoutState()
- {
- if (doingFullRepaint())
- return;
- LayoutState* state = m_layoutState;
- m_layoutState = state->m_next;
- state->destroy(renderArena());
- }
+ void popLayoutState(RenderObject*) { return popLayoutState(); } // Just doing this to keep popLayoutState() private and to make the subtree calls symmetrical.
bool shouldDisableLayoutStateForSubtree(RenderObject*) const;
@@ -159,6 +131,30 @@ public:
virtual void updateHitTestResult(HitTestResult&, const IntPoint&);
+ unsigned pageHeight() const { return m_pageHeight; }
+ void setPageHeight(unsigned height)
+ {
+ if (m_pageHeight != height) {
+ m_pageHeight = height;
+ markDescendantBlocksAndLinesForLayout();
+ }
+ }
+
+ // FIXME: These functions are deprecated. No code should be added that uses these.
+ int bestTruncatedAt() const { return m_legacyPrinting.m_bestTruncatedAt; }
+ void setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak = false);
+ int truncatedAt() const { return m_legacyPrinting.m_truncatedAt; }
+ void setTruncatedAt(int y)
+ {
+ m_legacyPrinting.m_truncatedAt = y;
+ m_legacyPrinting.m_bestTruncatedAt = 0;
+ m_legacyPrinting.m_truncatorWidth = 0;
+ m_legacyPrinting.m_forcedPageBreak = false;
+ }
+ const IntRect& printRect() const { return m_legacyPrinting.m_printRect; }
+ void setPrintRect(const IntRect& r) { m_legacyPrinting.m_printRect = r; }
+ // End deprecated functions.
+
// Notifications that this view became visible in a window, or will be
// removed from the window.
void didMoveOnscreen();
@@ -182,6 +178,26 @@ public: // used by layout function
int docHeight() const;
int docWidth() const;
+ // These functions may only be accessed by LayoutStateMaintainer.
+ bool pushLayoutState(RenderBox* renderer, const IntSize& offset, int pageHeight = 0, ColumnInfo* colInfo = 0)
+ {
+ // We push LayoutState even if layoutState is disabled because it stores layoutDelta too.
+ if (!doingFullRepaint() || renderer->hasColumns() || m_layoutState->isPaginated()) {
+ m_layoutState = new (renderArena()) LayoutState(m_layoutState, renderer, offset, pageHeight, colInfo);
+ return true;
+ }
+ return false;
+ }
+
+ void popLayoutState()
+ {
+ LayoutState* state = m_layoutState;
+ m_layoutState = state->m_next;
+ state->destroy(renderArena());
+ }
+
+ friend class LayoutStateMaintainer;
+
protected:
FrameView* m_frameView;
@@ -190,22 +206,31 @@ protected:
int m_selectionStartPos;
int m_selectionEndPos;
- // used to ignore viewport width when printing to the printer
- bool m_printImages;
- int m_truncatedAt;
+ // FIXME: Only used by embedded WebViews inside AppKit NSViews. Find a way to remove.
+ struct LegacyPrinting {
+ LegacyPrinting()
+ : m_bestTruncatedAt(0)
+ , m_truncatedAt(0)
+ , m_truncatorWidth(0)
+ , m_forcedPageBreak(false)
+ { }
+
+ int m_bestTruncatedAt;
+ int m_truncatedAt;
+ int m_truncatorWidth;
+ IntRect m_printRect;
+ bool m_forcedPageBreak;
+ };
+ LegacyPrinting m_legacyPrinting;
+ // End deprecated members.
int m_maximalOutlineSize; // Used to apply a fudge factor to dirty-rect checks on blocks/tables.
- IntRect m_printRect; // Used when printing.
typedef HashSet<RenderWidget*> RenderWidgetSet;
-
RenderWidgetSet m_widgets;
-
+
private:
- int m_bestTruncatedAt;
- int m_truncatorWidth;
- int m_minimumColumnHeight;
- bool m_forcedPageBreak;
+ unsigned m_pageHeight;
LayoutState* m_layoutState;
unsigned m_layoutStateDisableCount;
#if USE(ACCELERATED_COMPOSITING)
@@ -233,13 +258,14 @@ void toRenderView(const RenderView*);
class LayoutStateMaintainer : public Noncopyable {
public:
// ctor to push now
- LayoutStateMaintainer(RenderView* view, RenderBox* root, IntSize offset, bool disableState = false)
+ LayoutStateMaintainer(RenderView* view, RenderBox* root, IntSize offset, bool disableState = false, int pageHeight = 0, ColumnInfo* colInfo = 0)
: m_view(view)
, m_disabled(disableState)
, m_didStart(false)
, m_didEnd(false)
+ , m_didCreateLayoutState(false)
{
- push(root, offset);
+ push(root, offset, pageHeight, colInfo);
}
// ctor to maybe push later
@@ -248,6 +274,7 @@ public:
, m_disabled(false)
, m_didStart(false)
, m_didEnd(false)
+ , m_didCreateLayoutState(false)
{
}
@@ -256,12 +283,12 @@ public:
ASSERT(m_didStart == m_didEnd); // if this fires, it means that someone did a push(), but forgot to pop().
}
- void push(RenderBox* root, IntSize offset)
+ void push(RenderBox* root, IntSize offset, int pageHeight = 0, ColumnInfo* colInfo = 0)
{
ASSERT(!m_didStart);
// We push state even if disabled, because we still need to store layoutDelta
- m_view->pushLayoutState(root, offset);
- if (m_disabled)
+ m_didCreateLayoutState = m_view->pushLayoutState(root, offset, pageHeight, colInfo);
+ if (m_disabled && m_didCreateLayoutState)
m_view->disableLayoutState();
m_didStart = true;
}
@@ -270,9 +297,12 @@ public:
{
if (m_didStart) {
ASSERT(!m_didEnd);
- m_view->popLayoutState();
- if (m_disabled)
- m_view->enableLayoutState();
+ if (m_didCreateLayoutState) {
+ m_view->popLayoutState();
+ if (m_disabled)
+ m_view->enableLayoutState();
+ }
+
m_didEnd = true;
}
}
@@ -284,6 +314,7 @@ private:
bool m_disabled : 1; // true if the offset and clip part of layoutState is disabled
bool m_didStart : 1; // true if we did a push or disable
bool m_didEnd : 1; // true if we popped or re-enabled
+ bool m_didCreateLayoutState : 1; // true if we actually made a layout state.
};
} // namespace WebCore
diff --git a/WebCore/rendering/RootInlineBox.h b/WebCore/rendering/RootInlineBox.h
index ff98f24..d97d0b1 100644
--- a/WebCore/rendering/RootInlineBox.h
+++ b/WebCore/rendering/RootInlineBox.h
@@ -40,6 +40,7 @@ public:
, m_lineBreakPos(0)
, m_lineTop(0)
, m_lineBottom(0)
+ , m_paginationStrut(0)
{
}
@@ -57,6 +58,9 @@ public:
int lineTop() const { return m_lineTop; }
int lineBottom() const { return m_lineBottom; }
+ int paginationStrut() const { return m_paginationStrut; }
+ void setPaginationStrut(int s) { m_paginationStrut = s; }
+
int selectionTop() const;
int selectionBottom() const { return lineBottom(); }
int selectionHeight() const { return max(0, selectionBottom() - selectionTop()); }
@@ -141,6 +145,8 @@ private:
int m_lineTop;
int m_lineBottom;
+ int m_paginationStrut;
+
// Floats hanging off the line are pushed into this vector during layout. It is only
// good for as long as the line has not been marked dirty.
OwnPtr<Vector<RenderBox*> > m_floats;
diff --git a/WebCore/rendering/style/RenderStyle.cpp b/WebCore/rendering/style/RenderStyle.cpp
index 93cd8de..4b77d6b 100644
--- a/WebCore/rendering/style/RenderStyle.cpp
+++ b/WebCore/rendering/style/RenderStyle.cpp
@@ -441,6 +441,10 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
noninherited_flags._clear != other->noninherited_flags._clear)
return StyleDifferenceLayout;
+ // Check block flow direction.
+ if (inherited_flags._blockFlow != other->inherited_flags._blockFlow)
+ return StyleDifferenceLayout;
+
// Overflow returns a layout hint.
if (noninherited_flags._overflowX != other->noninherited_flags._overflowX ||
noninherited_flags._overflowY != other->noninherited_flags._overflowY)
@@ -1060,4 +1064,184 @@ const Color RenderStyle::visitedDependentColor(int colorProperty) const
return Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), unvisitedColor.alpha());
}
+Length RenderStyle::logicalWidth() const
+{
+ if (isVerticalBlockFlow())
+ return width();
+ return height();
+}
+
+Length RenderStyle::logicalHeight() const
+{
+ if (isVerticalBlockFlow())
+ return height();
+ return width();
+}
+
+Length RenderStyle::logicalMinWidth() const
+{
+ if (isVerticalBlockFlow())
+ return minWidth();
+ return minHeight();
+}
+
+Length RenderStyle::logicalMaxWidth() const
+{
+ if (isVerticalBlockFlow())
+ return maxWidth();
+ return maxHeight();
+}
+
+Length RenderStyle::logicalMinHeight() const
+{
+ if (isVerticalBlockFlow())
+ return minHeight();
+ return minWidth();
+}
+
+Length RenderStyle::logicalMaxHeight() const
+{
+ if (isVerticalBlockFlow())
+ return maxHeight();
+ return maxWidth();
+}
+
+unsigned short RenderStyle::borderBeforeWidth() const
+{
+ switch (blockFlow()) {
+ case TopToBottomBlockFlow:
+ return borderTopWidth();
+ case BottomToTopBlockFlow:
+ return borderBottomWidth();
+ case LeftToRightBlockFlow:
+ return borderLeftWidth();
+ case RightToLeftBlockFlow:
+ return borderRightWidth();
+ }
+ ASSERT_NOT_REACHED();
+ return borderTopWidth();
+}
+
+unsigned short RenderStyle::borderAfterWidth() const
+{
+ switch (blockFlow()) {
+ case TopToBottomBlockFlow:
+ return borderBottomWidth();
+ case BottomToTopBlockFlow:
+ return borderTopWidth();
+ case LeftToRightBlockFlow:
+ return borderRightWidth();
+ case RightToLeftBlockFlow:
+ return borderLeftWidth();
+ }
+ ASSERT_NOT_REACHED();
+ return borderBottomWidth();
+}
+
+unsigned short RenderStyle::borderStartWidth() const
+{
+ if (isVerticalBlockFlow())
+ return direction() == LTR ? borderLeftWidth() : borderRightWidth();
+ return direction() == LTR ? borderTopWidth() : borderBottomWidth();
+}
+
+unsigned short RenderStyle::borderEndWidth() const
+{
+ if (isVerticalBlockFlow())
+ return direction() == LTR ? borderRightWidth() : borderLeftWidth();
+ return direction() == LTR ? borderBottomWidth() : borderTopWidth();
+}
+
+Length RenderStyle::marginBefore() const
+{
+ switch (blockFlow()) {
+ case TopToBottomBlockFlow:
+ return marginTop();
+ case BottomToTopBlockFlow:
+ return marginBottom();
+ case LeftToRightBlockFlow:
+ return marginLeft();
+ case RightToLeftBlockFlow:
+ return marginRight();
+ }
+ ASSERT_NOT_REACHED();
+ return marginTop();
+}
+
+Length RenderStyle::marginAfter() const
+{
+ switch (blockFlow()) {
+ case TopToBottomBlockFlow:
+ return marginBottom();
+ case BottomToTopBlockFlow:
+ return marginTop();
+ case LeftToRightBlockFlow:
+ return marginRight();
+ case RightToLeftBlockFlow:
+ return marginLeft();
+ }
+ ASSERT_NOT_REACHED();
+ return marginBottom();
+}
+
+Length RenderStyle::marginStart() const
+{
+ if (isVerticalBlockFlow())
+ return direction() == LTR ? marginLeft() : marginRight();
+ return direction() == LTR ? marginTop() : marginBottom();
+}
+
+Length RenderStyle::marginEnd() const
+{
+ if (isVerticalBlockFlow())
+ return direction() == LTR ? marginRight() : marginLeft();
+ return direction() == LTR ? marginBottom() : marginTop();
+}
+
+Length RenderStyle::paddingBefore() const
+{
+ switch (blockFlow()) {
+ case TopToBottomBlockFlow:
+ return paddingTop();
+ case BottomToTopBlockFlow:
+ return paddingBottom();
+ case LeftToRightBlockFlow:
+ return paddingLeft();
+ case RightToLeftBlockFlow:
+ return paddingRight();
+ }
+ ASSERT_NOT_REACHED();
+ return paddingTop();
+}
+
+Length RenderStyle::paddingAfter() const
+{
+ switch (blockFlow()) {
+ case TopToBottomBlockFlow:
+ return paddingBottom();
+ case BottomToTopBlockFlow:
+ return paddingTop();
+ case LeftToRightBlockFlow:
+ return paddingRight();
+ case RightToLeftBlockFlow:
+ return paddingLeft();
+ }
+ ASSERT_NOT_REACHED();
+ return paddingBottom();
+}
+
+Length RenderStyle::paddingStart() const
+{
+ if (isVerticalBlockFlow())
+ return direction() == LTR ? paddingLeft() : paddingRight();
+ return direction() == LTR ? paddingTop() : paddingBottom();
+}
+
+Length RenderStyle::paddingEnd() const
+{
+ if (isVerticalBlockFlow())
+ return direction() == LTR ? paddingRight() : paddingLeft();
+ return direction() == LTR ? paddingBottom() : paddingTop();
+}
+
} // namespace WebCore
diff --git a/WebCore/rendering/style/RenderStyle.h b/WebCore/rendering/style/RenderStyle.h
index e696735..e287ab9 100644
--- a/WebCore/rendering/style/RenderStyle.h
+++ b/WebCore/rendering/style/RenderStyle.h
@@ -178,7 +178,8 @@ protected:
(_visuallyOrdered == other._visuallyOrdered) &&
(_force_backgrounds_to_white == other._force_backgrounds_to_white) &&
(_pointerEvents == other._pointerEvents) &&
- (_insideLink == other._insideLink);
+ (_insideLink == other._insideLink) &&
+ (_blockFlow == other._blockFlow);
}
bool operator!=(const InheritedFlags& other) const { return !(*this == other); }
@@ -204,6 +205,10 @@ protected:
unsigned _pointerEvents : 4; // EPointerEvents
unsigned _insideLink : 2; // EInsideLink
// 43 bits
+
+ // CSS Text Layout Module Level 3: Vertical writing support
+ unsigned _blockFlow : 2; // EBlockFlowDirection
+ // 45 bits
} inherited_flags;
// don't inherit
@@ -279,6 +284,7 @@ protected:
inherited_flags._force_backgrounds_to_white = false;
inherited_flags._pointerEvents = initialPointerEvents();
inherited_flags._insideLink = NotInsideLink;
+ inherited_flags._blockFlow = initialBlockFlow();
noninherited_flags._effectiveDisplay = noninherited_flags._originalDisplay = initialDisplay();
noninherited_flags._overflowX = initialOverflowX();
@@ -384,6 +390,13 @@ public:
Length maxWidth() const { return m_box->maxWidth(); }
Length minHeight() const { return m_box->minHeight(); }
Length maxHeight() const { return m_box->maxHeight(); }
+
+ Length logicalWidth() const;
+ Length logicalHeight() const;
+ Length logicalMinWidth() const;
+ Length logicalMaxWidth() const;
+ Length logicalMinHeight() const;
+ Length logicalMaxHeight() const;
const BorderData& border() const { return surround->border; }
const BorderValue& borderLeft() const { return surround->border.left(); }
@@ -411,6 +424,11 @@ public:
unsigned short borderBottomWidth() const { return surround->border.borderBottomWidth(); }
EBorderStyle borderBottomStyle() const { return surround->border.bottom().style(); }
bool borderBottomIsTransparent() const { return surround->border.bottom().isTransparent(); }
+
+ unsigned short borderBeforeWidth() const;
+ unsigned short borderAfterWidth() const;
+ unsigned short borderStartWidth() const;
+ unsigned short borderEndWidth() const;
unsigned short outlineSize() const { return max(0, outlineWidth() + outlineOffset()); }
unsigned short outlineWidth() const
@@ -576,12 +594,20 @@ public:
Length marginBottom() const { return surround->margin.bottom(); }
Length marginLeft() const { return surround->margin.left(); }
Length marginRight() const { return surround->margin.right(); }
+ Length marginBefore() const;
+ Length marginAfter() const;
+ Length marginStart() const;
+ Length marginEnd() const;
LengthBox paddingBox() const { return surround->padding; }
Length paddingTop() const { return surround->padding.top(); }
Length paddingBottom() const { return surround->padding.bottom(); }
Length paddingLeft() const { return surround->padding.left(); }
Length paddingRight() const { return surround->padding.right(); }
+ Length paddingBefore() const;
+ Length paddingAfter() const;
+ Length paddingStart() const;
+ Length paddingEnd() const;
ECursor cursor() const { return static_cast<ECursor>(inherited_flags._cursor_style); }
@@ -712,6 +738,7 @@ public:
bool textSizeAdjust() const { return rareInheritedData->textSizeAdjust; }
ETextSecurity textSecurity() const { return static_cast<ETextSecurity>(rareInheritedData->textSecurity); }
+<<<<<<< HEAD
#ifdef ANDROID_CSS_RING
// called when building nav cache to determine if the ring data is unchanged
const void* ringData() const { return reinterpret_cast<const void*>(rareInheritedData.get()); }
@@ -728,6 +755,10 @@ public:
#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
Color tapHighlightColor() const { return rareInheritedData->tapHighlightColor; }
#endif
+=======
+ EBlockFlowDirection blockFlow() const { return static_cast<EBlockFlowDirection>(inherited_flags._blockFlow); }
+ bool isVerticalBlockFlow() const { return blockFlow() == TopToBottomBlockFlow || blockFlow() == BottomToTopBlockFlow; }
+>>>>>>> webkit.org at r67908
// attribute setter methods
@@ -1123,6 +1154,8 @@ public:
originalDisplay() == INLINE_BOX || originalDisplay() == INLINE_TABLE;
}
+ void setBlockFlow(EBlockFlowDirection v) { inherited_flags._blockFlow = v; }
+
// To tell if this style matched attribute selectors. This makes it impossible to share.
bool affectedByAttributeSelectors() const { return m_affectedByAttributeSelectors; }
void setAffectedByAttributeSelectors() { m_affectedByAttributeSelectors = true; }
@@ -1162,6 +1195,7 @@ public:
static ECaptionSide initialCaptionSide() { return CAPTOP; }
static EClear initialClear() { return CNONE; }
static TextDirection initialDirection() { return LTR; }
+ static EBlockFlowDirection initialBlockFlow() { return TopToBottomBlockFlow; }
static EDisplay initialDisplay() { return INLINE; }
static EEmptyCell initialEmptyCells() { return SHOW; }
static EFloat initialFloating() { return FNONE; }
@@ -1290,6 +1324,18 @@ private:
ContentData* prepareToSetContent(StringImpl*, bool add);
};
+inline int adjustForAbsoluteZoom(int value, const RenderStyle* style)
+{
+ double zoomFactor = style->effectiveZoom();
+ if (zoomFactor == 1)
+ return value;
+ // Needed because computeLengthInt truncates (rather than rounds) when scaling up.
+ if (zoomFactor > 1)
+ value++;
+
+ return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(value / zoomFactor);
+}
+
} // namespace WebCore
#endif // RenderStyle_h
diff --git a/WebCore/rendering/style/RenderStyleConstants.h b/WebCore/rendering/style/RenderStyleConstants.h
index a78321f..94d30d5 100644
--- a/WebCore/rendering/style/RenderStyleConstants.h
+++ b/WebCore/rendering/style/RenderStyleConstants.h
@@ -128,6 +128,11 @@ enum EUnicodeBidi {
UBNormal, Embed, Override
};
+// CSS Text Layout Module Level 3: Vertical writing support
+enum EBlockFlowDirection {
+ TopToBottomBlockFlow, RightToLeftBlockFlow, LeftToRightBlockFlow, BottomToTopBlockFlow
+};
+
enum EFillAttachment {
ScrollBackgroundAttachment, LocalBackgroundAttachment, FixedBackgroundAttachment
};
diff --git a/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp b/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp
new file mode 100644
index 0000000..3283b35
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * 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"
+
+#if ENABLE(SVG)
+#include "SVGTextLayoutAttributes.h"
+
+#include <stdio.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+SVGTextLayoutAttributes::SVGTextLayoutAttributes()
+{
+}
+
+void SVGTextLayoutAttributes::fillWithEmptyValues(unsigned length)
+{
+ m_xValues.fill(emptyValue(), length);
+ m_yValues.fill(emptyValue(), length);
+ m_dxValues.fill(emptyValue(), length);
+ m_dyValues.fill(emptyValue(), length);
+ m_rotateValues.fill(emptyValue(), length);
+}
+
+float SVGTextLayoutAttributes::emptyValue()
+{
+ static float s_emptyValue = std::numeric_limits<float>::max() - 1;
+ return s_emptyValue;
+}
+
+static inline void dumpLayoutVector(Vector<float>& values)
+{
+ if (values.isEmpty()) {
+ fprintf(stderr, "empty");
+ return;
+ }
+
+ unsigned size = values.size();
+ for (unsigned i = 0; i < size; ++i) {
+ float value = values.at(i);
+ if (value == SVGTextLayoutAttributes::emptyValue())
+ fprintf(stderr, "x ");
+ else
+ fprintf(stderr, "%lf ", value);
+ }
+}
+
+void SVGTextLayoutAttributes::dump()
+{
+ fprintf(stderr, "x values: ");
+ dumpLayoutVector(m_xValues);
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "y values: ");
+ dumpLayoutVector(m_yValues);
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "dx values: ");
+ dumpLayoutVector(m_dxValues);
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "dy values: ");
+ dumpLayoutVector(m_dyValues);
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "rotate values: ");
+ dumpLayoutVector(m_rotateValues);
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "character data values:\n");
+ Vector<CharacterData>::iterator end = m_characterDataValues.end();
+ for (Vector<CharacterData>::iterator it = m_characterDataValues.begin(); it != end; ++it) {
+ CharacterData& data = *it;
+ fprintf(stderr, "| {spansCharacters=%i, glyphName='%s', unicodeString='%s', width=%lf, height=%lf}\n",
+ data.spansCharacters, data.glyphName.utf8().data(), data.unicodeString.utf8().data(), data.width, data.height);
+ }
+ fprintf(stderr, "\n");
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/svg/SVGTextLayoutAttributes.h b/WebCore/rendering/svg/SVGTextLayoutAttributes.h
new file mode 100644
index 0000000..d88b356
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextLayoutAttributes.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef SVGTextLayoutAttributes_h
+#define SVGTextLayoutAttributes_h
+
+#if ENABLE(SVG)
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class SVGTextLayoutAttributes {
+public:
+ SVGTextLayoutAttributes();
+
+ void fillWithEmptyValues(unsigned length);
+ void dump();
+
+ Vector<float>& xValues() { return m_xValues; }
+ const Vector<float>& xValues() const { return m_xValues; }
+
+ Vector<float>& yValues() { return m_yValues; }
+ const Vector<float>& yValues() const { return m_yValues; }
+
+ Vector<float>& dxValues() { return m_dxValues; }
+ const Vector<float>& dxValues() const { return m_dxValues; }
+
+ Vector<float>& dyValues() { return m_dyValues; }
+ const Vector<float>& dyValues() const { return m_dyValues; }
+
+ Vector<float>& rotateValues() { return m_rotateValues; }
+ const Vector<float>& rotateValues() const { return m_rotateValues; }
+
+ static float emptyValue();
+
+ struct CharacterData {
+ CharacterData()
+ : spansCharacters(0)
+ , width(0)
+ , height(0)
+ {
+ }
+
+ // When multiple unicode characters map to a single glyph (eg. 'ffi' ligature)
+ // 'spansCharacters' contains the number of characters this glyph spans.
+ int spansCharacters;
+
+ // The 'glyphName' / 'unicodeString' pair is needed for kerning calculations.
+ String glyphName;
+ String unicodeString;
+
+ // 'width' and 'height' hold the size of this glyph/character.
+ float width;
+ float height;
+ };
+
+ Vector<CharacterData>& characterDataValues() { return m_characterDataValues; }
+ const Vector<CharacterData>& characterDataValues() const { return m_characterDataValues; }
+
+private:
+ Vector<float> m_xValues;
+ Vector<float> m_yValues;
+ Vector<float> m_dxValues;
+ Vector<float> m_dyValues;
+ Vector<float> m_rotateValues;
+ Vector<CharacterData> m_characterDataValues;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif
diff --git a/WebCore/rendering/svg/SVGTextLayoutBuilder.cpp b/WebCore/rendering/svg/SVGTextLayoutBuilder.cpp
new file mode 100644
index 0000000..0b3a752
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextLayoutBuilder.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * 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"
+
+#if ENABLE(SVG)
+#include "SVGTextLayoutBuilder.h"
+
+#include "RenderSVGInlineText.h"
+#include "RenderSVGText.h"
+#include "SVGTextLayoutUtilities.h"
+#include "SVGTextPositioningElement.h"
+
+// Set to a value > 0 to dump the layout vectors
+#define DUMP_LAYOUT_VECTORS 0
+
+namespace WebCore {
+
+SVGTextLayoutBuilder::SVGTextLayoutBuilder()
+{
+}
+
+void SVGTextLayoutBuilder::buildLayoutAttributesForTextSubtree(RenderSVGText* textRoot)
+{
+ ASSERT(textRoot);
+ m_scopes.clear();
+
+ // Build layout scopes.
+ unsigned atCharacter = 0;
+ buildLayoutScopes(textRoot, atCharacter);
+
+ if (!atCharacter)
+ return;
+
+ // Add outermost scope, after text length is known.
+ LayoutScope scope;
+ buildLayoutScope(scope, textRoot, 0, atCharacter);
+ m_scopes.prepend(scope);
+
+ // Build layout information respecting scope of attribute values.
+ buildLayoutAttributesFromScopes();
+
+ atCharacter = 0;
+ propagateLayoutAttributes(textRoot, atCharacter);
+}
+
+static inline void copyToDestinationVector(Vector<float>& destination, unsigned destinationStartOffset, Vector<float>& source, unsigned sourceStartOffset, unsigned length)
+{
+ ASSERT(destinationStartOffset + length <= destination.size());
+
+ Vector<float>::iterator sourceBegin = source.begin() + sourceStartOffset;
+ std::copy(sourceBegin, sourceBegin + length, destination.begin() + destinationStartOffset);
+}
+
+static inline void copyToDestinationVectorIfSourceRangeIsNotEmpty(Vector<float>& destination, unsigned destinationStartOffset, Vector<float>& source, unsigned sourceStartOffset, unsigned length)
+{
+ bool rangeEmpty = true;
+
+ unsigned size = sourceStartOffset + length;
+ for (unsigned i = sourceStartOffset; i < size; ++i) {
+ if (source.at(i) == SVGTextLayoutAttributes::emptyValue())
+ continue;
+ rangeEmpty = false;
+ break;
+ }
+
+ if (rangeEmpty)
+ return;
+
+ destination.resize(length);
+ copyToDestinationVector(destination, destinationStartOffset, source, sourceStartOffset, length);
+}
+
+void SVGTextLayoutBuilder::propagateLayoutAttributes(RenderObject* start, unsigned& atCharacter)
+{
+ for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
+ if (!child->isSVGInlineText()) {
+ if (child->isSVGInline())
+ propagateLayoutAttributes(child, atCharacter);
+ continue;
+ }
+
+ RenderSVGInlineText* text = static_cast<RenderSVGInlineText*>(child);
+ unsigned textLength = text->textLength();
+
+ // Build layout attributes for a single RenderSVGInlineText renderer.
+ SVGTextLayoutAttributes attributes;
+
+ // The x value list should always be as large as the text length.
+ // Any values that are empty will be filled in by the actual text layout process later,
+ // as we need to be able to query the x/y position for every character through SVG DOM.
+ attributes.xValues().resize(textLength);
+ copyToDestinationVector(attributes.xValues(), 0, m_attributes.xValues(), atCharacter, textLength);
+
+ // Same for the y value list.
+ attributes.yValues().resize(textLength);
+ copyToDestinationVector(attributes.yValues(), 0, m_attributes.yValues(), atCharacter, textLength);
+
+ // The dx/dy/rotate value lists may be empty.
+ copyToDestinationVectorIfSourceRangeIsNotEmpty(attributes.dxValues(), 0, m_attributes.dxValues(), atCharacter, textLength);
+ copyToDestinationVectorIfSourceRangeIsNotEmpty(attributes.dyValues(), 0, m_attributes.dyValues(), atCharacter, textLength);
+ copyToDestinationVectorIfSourceRangeIsNotEmpty(attributes.rotateValues(), 0, m_attributes.rotateValues(), atCharacter, textLength);
+
+ // Build CharacterData, which will be used to detect ligatures, holds kerning pairs (glyph name, unicode string) and character metrics.
+ measureCharacters(text, attributes);
+
+#if DUMP_LAYOUT_VECTORS > 0
+ fprintf(stderr, "Dumping layout vector for RenderSVGInlineText, renderer=%p, node=%p\n", text, text->node());
+ attributes.dump();
+#endif
+
+ text->storeLayoutAttributes(attributes);
+ atCharacter += text->textLength();
+ }
+}
+
+void SVGTextLayoutBuilder::buildLayoutScopes(RenderObject* start, unsigned& atCharacter)
+{
+ for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
+ if (child->isSVGInlineText()) {
+ atCharacter += toRenderText(child)->textLength();
+ continue;
+ }
+
+ if (!child->isSVGInline())
+ continue;
+
+ unsigned textContentStart = atCharacter;
+ buildLayoutScopes(child, atCharacter);
+
+ LayoutScope scope;
+ buildLayoutScope(scope, child, textContentStart, atCharacter - textContentStart);
+ m_scopes.append(scope);
+ }
+}
+
+static inline void fillDestinationVectorWithLastSourceValue(Vector<float>& destination, unsigned destinationStartOffset, Vector<float>& source, unsigned length)
+{
+ if (source.isEmpty())
+ return;
+
+ float lastValue = source.last();
+
+ unsigned rotateValuesSize = source.size();
+ for (unsigned i = rotateValuesSize; i < length; ++i) {
+ ASSERT(i + destinationStartOffset < destination.size());
+ destination.at(i + destinationStartOffset) = lastValue;
+ }
+}
+
+void SVGTextLayoutBuilder::buildLayoutAttributesFromScopes()
+{
+ ASSERT(!m_scopes.isEmpty());
+
+ unsigned totalLength = m_scopes.first().textContentLength;
+ if (!totalLength)
+ return;
+
+ m_attributes.fillWithEmptyValues(totalLength);
+
+ // Build final list of x/y/dx/dy/rotate values for each character stores in the <text> subtree.
+ for (unsigned atScope = 0; atScope < m_scopes.size(); ++atScope) {
+ LayoutScope& scope = m_scopes.at(atScope);
+ SVGTextLayoutAttributes& attributes = scope.attributes;
+
+ copyToDestinationVector(m_attributes.xValues(), scope.textContentStart, attributes.xValues(), 0, attributes.xValues().size());
+ copyToDestinationVector(m_attributes.yValues(), scope.textContentStart, attributes.yValues(), 0, attributes.yValues().size());
+ copyToDestinationVector(m_attributes.dxValues(), scope.textContentStart, attributes.dxValues(), 0, attributes.dxValues().size());
+ copyToDestinationVector(m_attributes.dyValues(), scope.textContentStart, attributes.dyValues(), 0, attributes.dyValues().size());
+ copyToDestinationVector(m_attributes.rotateValues(), scope.textContentStart, attributes.rotateValues(), 0, attributes.rotateValues().size());
+
+ // In horizontal (vertical) writing modes, the last y (x) value in the scope is the default y (x) value for all following characters, unless explicitely overriden.
+ if (scope.isVerticalWritingMode)
+ fillDestinationVectorWithLastSourceValue(m_attributes.xValues(), scope.textContentStart, attributes.xValues(), scope.textContentLength);
+ else
+ fillDestinationVectorWithLastSourceValue(m_attributes.yValues(), scope.textContentStart, attributes.yValues(), scope.textContentLength);
+
+ // The last rotation value in the scope is the default rotation for all following character, unless explicitely overriden.
+ fillDestinationVectorWithLastSourceValue(m_attributes.rotateValues(), scope.textContentStart, attributes.rotateValues(), scope.textContentLength);
+ }
+}
+
+void SVGTextLayoutBuilder::measureCharacters(RenderSVGInlineText* text, SVGTextLayoutAttributes& attributes)
+{
+ ASSERT(text);
+ ASSERT(text->style());
+ const Font& font = text->style()->font();
+ const UChar* characters = text->characters();
+ int length = text->textLength();
+
+ TextRun run(0, 0);
+ run.disableSpacing();
+ run.disableRoundingHacks();
+
+ int charsConsumed = 0;
+ for (int position = 0; position < length; position += charsConsumed) {
+ run.setText(characters + position, 1);
+ int extraCharsAvailable = length - position - 1;
+
+ SVGTextLayoutAttributes::CharacterData characterData;
+ characterData.width = font.floatWidth(run, extraCharsAvailable, characterData.spansCharacters, characterData.glyphName);
+ characterData.height = font.height();
+ characterData.unicodeString = String(characters + position, characterData.spansCharacters);
+ attributes.characterDataValues().append(characterData);
+
+ charsConsumed = characterData.spansCharacters;
+ }
+}
+
+static inline void extractFloatValuesFromSVGLengthList(SVGElement* lengthContext, SVGLengthList* list, Vector<float>& floatValues, int textContentLength)
+{
+ ASSERT(lengthContext);
+ ASSERT(list);
+ ASSERT(textContentLength >= 0);
+
+ ExceptionCode ec = 0;
+ int length = list->numberOfItems();
+ if (length > textContentLength)
+ length = textContentLength;
+
+ for (int i = 0; i < length; ++i) {
+ SVGLength length(list->getItem(i, ec));
+ ASSERT(!ec);
+ floatValues.append(length.value(lengthContext));
+ }
+}
+
+static inline void extractFloatValuesFromSVGNumberList(SVGNumberList* list, Vector<float>& floatValues, int textContentLength)
+{
+ ASSERT(list);
+ ASSERT(textContentLength >= 0);
+
+ ExceptionCode ec = 0;
+ int length = list->numberOfItems();
+ if (length > textContentLength)
+ length = textContentLength;
+
+ for (int i = 0; i < length; ++i) {
+ float length(list->getItem(i, ec));
+ ASSERT(!ec);
+ floatValues.append(length);
+ }
+}
+
+static inline SVGTextPositioningElement* svgTextPositioningElementForInlineRenderer(RenderObject* renderer)
+{
+ ASSERT(renderer);
+ ASSERT(renderer->isSVGText() || renderer->isSVGInline());
+
+ Node* node = renderer->node();
+ ASSERT(node);
+ ASSERT(node->isSVGElement());
+
+ if (!node->hasTagName(SVGNames::textTag)
+ && !node->hasTagName(SVGNames::tspanTag)
+#if ENABLE(SVG_FONTS)
+ && !node->hasTagName(SVGNames::altGlyphTag)
+#endif
+ && !node->hasTagName(SVGNames::trefTag))
+ return 0;
+
+ return static_cast<SVGTextPositioningElement*>(node);
+}
+
+void SVGTextLayoutBuilder::buildLayoutScope(LayoutScope& scope, RenderObject* renderer, unsigned textContentStart, unsigned textContentLength)
+{
+ ASSERT(renderer);
+ ASSERT(renderer->style());
+
+ scope.isVerticalWritingMode = isVerticalWritingMode(renderer->style()->svgStyle());
+ scope.textContentStart = textContentStart;
+ scope.textContentLength = textContentLength;
+
+ SVGTextPositioningElement* element = svgTextPositioningElementForInlineRenderer(renderer);
+ if (!element)
+ return;
+
+ SVGTextLayoutAttributes& attributes = scope.attributes;
+ extractFloatValuesFromSVGLengthList(element, element->x(), attributes.xValues(), textContentLength);
+ extractFloatValuesFromSVGLengthList(element, element->y(), attributes.yValues(), textContentLength);
+ extractFloatValuesFromSVGLengthList(element, element->dx(), attributes.dxValues(), textContentLength);
+ extractFloatValuesFromSVGLengthList(element, element->dy(), attributes.dyValues(), textContentLength);
+ extractFloatValuesFromSVGNumberList(element->rotate(), attributes.rotateValues(), textContentLength);
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/rendering/svg/SVGTextLayoutBuilder.h b/WebCore/rendering/svg/SVGTextLayoutBuilder.h
new file mode 100644
index 0000000..6df7fa1
--- /dev/null
+++ b/WebCore/rendering/svg/SVGTextLayoutBuilder.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef SVGTextLayoutBuilder_h
+#define SVGTextLayoutBuilder_h
+
+#if ENABLE(SVG)
+#include "SVGTextLayoutAttributes.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class RenderObject;
+class RenderSVGInlineText;
+class RenderSVGText;
+
+class SVGTextLayoutBuilder : public Noncopyable {
+public:
+ SVGTextLayoutBuilder();
+ void buildLayoutAttributesForTextSubtree(RenderSVGText*);
+
+private:
+ struct LayoutScope {
+ LayoutScope()
+ : isVerticalWritingMode(false)
+ , textContentStart(0)
+ , textContentLength(0)
+ {
+ }
+
+ bool isVerticalWritingMode;
+ unsigned textContentStart;
+ unsigned textContentLength;
+ SVGTextLayoutAttributes attributes;
+ };
+
+ void buildLayoutScopes(RenderObject*, unsigned& atCharacter);
+ void buildLayoutScope(LayoutScope&, RenderObject*, unsigned textContentStart, unsigned textContentLength);
+ void buildLayoutAttributesFromScopes();
+ void propagateLayoutAttributes(RenderObject*, unsigned& atCharacter);
+ void measureCharacters(RenderSVGInlineText*, SVGTextLayoutAttributes&);
+
+private:
+ Vector<LayoutScope> m_scopes;
+ SVGTextLayoutAttributes m_attributes;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif