diff options
author | Steve Block <steveblock@google.com> | 2010-09-29 17:32:26 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-09-29 17:35:08 +0100 |
commit | 68513a70bcd92384395513322f1b801e7bf9c729 (patch) | |
tree | 161b50f75a5921d61731bb25e730005994fcec85 /WebCore/rendering | |
parent | fd5c6425ce58eb75211be7718d5dee960842a37e (diff) | |
download | external_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')
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(§ion()->style()->borderLeft(), section()->style()->visitedDependentColor(left), BROWGROUP)); + result = chooseBorder(result, CollapsedBorderValue(§ion()->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(§ion()->style()->borderRight(), section()->style()->visitedDependentColor(right), BROWGROUP)); + result = chooseBorder(result, CollapsedBorderValue(§ion()->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 |