diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-07 11:21:11 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-07 11:21:11 +0200 |
commit | 2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47 (patch) | |
tree | 988e8c5b116dd0466244ae2fe5af8ee9be926d76 /Source/WebCore/rendering | |
parent | dd91e772430dc294e3bf478c119ef8d43c0a3358 (diff) | |
download | qtwebkit-2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47.tar.gz |
Imported WebKit commit 7e538425aa020340619e927792f3d895061fb54b (http://svn.webkit.org/repository/webkit/trunk@116286)
Diffstat (limited to 'Source/WebCore/rendering')
235 files changed, 8382 insertions, 5110 deletions
diff --git a/Source/WebCore/rendering/AutoTableLayout.cpp b/Source/WebCore/rendering/AutoTableLayout.cpp index 2fa064f40..744a12b91 100644 --- a/Source/WebCore/rendering/AutoTableLayout.cpp +++ b/Source/WebCore/rendering/AutoTableLayout.cpp @@ -251,8 +251,8 @@ void AutoTableLayout::computePreferredLogicalWidths(LayoutUnit& minWidth, Layout if (scaleColumns) { maxNonPercent = maxNonPercent * 100 / max(remainingPercent, epsilon); - maxWidth = max(maxWidth, static_cast<int>(min(maxNonPercent, numeric_limits<LayoutUnit>::max() / 2.0f))); - maxWidth = max(maxWidth, static_cast<int>(min(maxPercent, numeric_limits<LayoutUnit>::max() / 2.0f))); + maxWidth = max<int>(maxWidth, static_cast<int>(min(maxNonPercent, MAX_LAYOUT_UNIT / 2.0f))); + maxWidth = max<int>(maxWidth, static_cast<int>(min(maxPercent, MAX_LAYOUT_UNIT / 2.0f))); } maxWidth = max<int>(maxWidth, spanMaxLogicalWidth); @@ -266,8 +266,8 @@ void AutoTableLayout::computePreferredLogicalWidths(LayoutUnit& minWidth, Layout minWidth = max<int>(minWidth, tableLogicalWidth.value()); maxWidth = minWidth; } else if (!remainingPercent && maxNonPercent) { - // if there was no remaining percent, maxWidth is invalid. - maxWidth = intMaxForLength; + // if there was no remaining percent, maxWidth is invalid + maxWidth = MAX_LAYOUT_UNIT; } Length tableLogicalMinWidth = m_table->style()->logicalMinWidth(); @@ -402,13 +402,23 @@ int AutoTableLayout::calcEffectiveLogicalWidth() } } else if (allColsArePercent) { // In this case, we just split the colspan's min amd max widths following the percentage. + int allocatedMinLogicalWidth = 0; + float allocatedMaxLogicalWidth = 0; for (unsigned pos = effCol; pos < lastCol; ++pos) { ASSERT(m_layoutStruct[pos].logicalWidth.isPercent() || m_layoutStruct[pos].effectiveLogicalWidth.isPercent()); // |allColsArePercent| means that either the logicalWidth *or* the effectiveLogicalWidth are percents, handle both of them here. float percent = m_layoutStruct[pos].logicalWidth.isPercent() ? m_layoutStruct[pos].logicalWidth.percent() : m_layoutStruct[pos].effectiveLogicalWidth.percent(); - m_layoutStruct[pos].effectiveMinLogicalWidth = max(m_layoutStruct[pos].effectiveMinLogicalWidth, static_cast<int>(percent * cellMinLogicalWidth / totalPercent)); - m_layoutStruct[pos].effectiveMaxLogicalWidth = percent * cellMaxLogicalWidth / totalPercent; + int columnMinLogicalWidth = static_cast<int>(percent * cellMinLogicalWidth / totalPercent); + float columnMaxLogicalWidth = percent * cellMaxLogicalWidth / totalPercent; + m_layoutStruct[pos].effectiveMinLogicalWidth = max(m_layoutStruct[pos].effectiveMinLogicalWidth, columnMinLogicalWidth); + m_layoutStruct[pos].effectiveMaxLogicalWidth = columnMaxLogicalWidth; + allocatedMinLogicalWidth += columnMinLogicalWidth; + allocatedMaxLogicalWidth += columnMaxLogicalWidth; } + ASSERT(allocatedMinLogicalWidth <= cellMinLogicalWidth); + ASSERT(allocatedMaxLogicalWidth <= cellMaxLogicalWidth); + cellMinLogicalWidth -= allocatedMinLogicalWidth; + cellMaxLogicalWidth -= allocatedMaxLogicalWidth; } else { float remainingMaxLogicalWidth = spanMaxLogicalWidth; int remainingMinLogicalWidth = spanMinLogicalWidth; @@ -551,7 +561,7 @@ void AutoTableLayout::layout() for (size_t i = 0; i < nEffCols; ++i) { Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; if (logicalWidth.isPercent()) { - int cellLogicalWidth = max<int>(m_layoutStruct[i].effectiveMinLogicalWidth, logicalWidth.calcMinValue(tableLogicalWidth)); + int cellLogicalWidth = max<int>(m_layoutStruct[i].effectiveMinLogicalWidth, minimumValueForLength(logicalWidth, tableLogicalWidth)); available += m_layoutStruct[i].computedLogicalWidth - cellLogicalWidth; m_layoutStruct[i].computedLogicalWidth = cellLogicalWidth; } diff --git a/Source/WebCore/rendering/ColumnInfo.h b/Source/WebCore/rendering/ColumnInfo.h index c8191cf1d..e462a84a5 100644 --- a/Source/WebCore/rendering/ColumnInfo.h +++ b/Source/WebCore/rendering/ColumnInfo.h @@ -83,10 +83,10 @@ public: m_maximumDistanceBetweenForcedBreaks = 0; m_forcedBreakOffset = 0; } - void addForcedBreak(int offsetFromFirstPage) + void addForcedBreak(LayoutUnit offsetFromFirstPage) { ASSERT(!m_columnHeight); - int distanceFromLastBreak = offsetFromFirstPage - m_forcedBreakOffset; + LayoutUnit distanceFromLastBreak = offsetFromFirstPage - m_forcedBreakOffset; if (!distanceFromLastBreak) return; m_forcedBreaks++; diff --git a/Source/WebCore/rendering/EllipsisBox.cpp b/Source/WebCore/rendering/EllipsisBox.cpp index e403fe667..5969a3222 100644 --- a/Source/WebCore/rendering/EllipsisBox.cpp +++ b/Source/WebCore/rendering/EllipsisBox.cpp @@ -33,7 +33,7 @@ namespace WebCore { void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext* context = paintInfo.context; - RenderStyle* style = m_renderer->style(m_firstLine); + RenderStyle* style = m_renderer->style(isFirstLineStyle()); Color textColor = style->visitedDependentColor(CSSPropertyColor); if (textColor != context->fillColor()) context->setFillColor(textColor, style->colorSpace()); @@ -68,17 +68,17 @@ void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, La // Paint the markup box LayoutPoint adjustedPaintOffset = paintOffset; adjustedPaintOffset.move(x() + m_logicalWidth - m_markupBox->x(), - y() + style->fontMetrics().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(m_firstLine)->fontMetrics().ascent())); + y() + style->fontMetrics().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(isFirstLineStyle())->fontMetrics().ascent())); m_markupBox->paint(paintInfo, adjustedPaintOffset, lineTop, lineBottom); } } IntRect EllipsisBox::selectionRect() { - RenderStyle* style = m_renderer->style(m_firstLine); + RenderStyle* style = m_renderer->style(isFirstLineStyle()); const Font& font = style->font(); // FIXME: Why is this always LTR? Fix by passing correct text run flags below. - return enclosingIntRect(font.selectionRectForText(RenderBlock::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), IntPoint(x(), y() + root()->selectionTop()), root()->selectionHeight())); + return enclosingIntRect(font.selectionRectForText(RenderBlock::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), IntPoint(x(), y() + root()->selectionTopAdjustedForPrecedingBlock()), root()->selectionHeightAdjustedForPrecedingBlock())); } void EllipsisBox::paintSelection(GraphicsContext* context, const LayoutPoint& paintOffset, RenderStyle* style, const Font& font) @@ -108,9 +108,9 @@ bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu // Hit test the markup box. if (m_markupBox) { - RenderStyle* style = m_renderer->style(m_firstLine); + RenderStyle* style = m_renderer->style(isFirstLineStyle()); LayoutUnit mtx = adjustedLocation.x() + m_logicalWidth - m_markupBox->x(); - LayoutUnit mty = adjustedLocation.y() + style->fontMetrics().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(m_firstLine)->fontMetrics().ascent()); + LayoutUnit mty = adjustedLocation.y() + style->fontMetrics().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(isFirstLineStyle())->fontMetrics().ascent()); if (m_markupBox->nodeAtPoint(request, result, pointInContainer, LayoutPoint(mtx, mty), lineTop, lineBottom)) { renderer()->updateHitTestResult(result, pointInContainer - LayoutSize(mtx, mty)); return true; diff --git a/Source/WebCore/rendering/FilterEffectObserver.h b/Source/WebCore/rendering/FilterEffectObserver.h deleted file mode 100644 index 7573497ce..000000000 --- a/Source/WebCore/rendering/FilterEffectObserver.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef FilterEffectObserver_h -#define FilterEffectObserver_h - -#if ENABLE(CSS_FILTERS) - -namespace WebCore { - -class FilterEffectObserver { -public: - virtual ~FilterEffectObserver() { } - virtual void filterNeedsRepaint() = 0; -}; - -} // namespace WebCore - -#endif // ENABLE(CSS_FILTERS) - -#endif // FilterEffectObserver_h diff --git a/Source/WebCore/rendering/FilterEffectRenderer.cpp b/Source/WebCore/rendering/FilterEffectRenderer.cpp index af5ecaf27..54e8c1cf5 100644 --- a/Source/WebCore/rendering/FilterEffectRenderer.cpp +++ b/Source/WebCore/rendering/FilterEffectRenderer.cpp @@ -35,7 +35,6 @@ #include "FEDropShadow.h" #include "FEGaussianBlur.h" #include "FEMerge.h" -#include "FilterEffectObserver.h" #include "FloatConversion.h" #include "RenderLayer.h" @@ -46,6 +45,7 @@ #include "CustomFilterProgram.h" #include "CustomFilterOperation.h" #include "FECustomFilter.h" +#include "FrameView.h" #include "Settings.h" #endif @@ -65,8 +65,15 @@ static inline void lastMatrixRow(Vector<float>& parameters) parameters.append(1); parameters.append(0); } - - + +inline bool isFilterSizeValid(FloatRect rect) +{ + if (rect.width() < 0 || rect.width() > kMaxFilterSize + || rect.height() < 0 || rect.height() > kMaxFilterSize) + return false; + return true; +} + #if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) static bool isCSSCustomFilterEnabled(Document* document) { @@ -76,9 +83,16 @@ static bool isCSSCustomFilterEnabled(Document* document) } #endif -FilterEffectRenderer::FilterEffectRenderer(FilterEffectObserver* observer) - : m_observer(observer) +FilterEffectRenderer::FilterEffectRenderer() + : m_topOutset(0) + , m_rightOutset(0) + , m_bottomOutset(0) + , m_leftOutset(0) , m_graphicsBufferAttached(false) + , m_hasFilterThatMovesPixels(false) +#if ENABLE(CSS_SHADERS) + , m_hasCustomShaderFilter(false) +#endif { setFilterResolution(FloatSize(1, 1)); m_sourceGraphic = SourceGraphic::create(this); @@ -86,9 +100,6 @@ FilterEffectRenderer::FilterEffectRenderer(FilterEffectObserver* observer) FilterEffectRenderer::~FilterEffectRenderer() { -#if ENABLE(CSS_SHADERS) - removeCustomFilterClients(); -#endif } GraphicsContext* FilterEffectRenderer::inputContext() @@ -96,14 +107,18 @@ GraphicsContext* FilterEffectRenderer::inputContext() return sourceImage() ? sourceImage()->context() : 0; } -void FilterEffectRenderer::build(Document* document, const FilterOperations& operations) +bool FilterEffectRenderer::build(Document* document, const FilterOperations& operations) { #if !ENABLE(CSS_SHADERS) || !ENABLE(WEBGL) UNUSED_PARAM(document); -#else - CustomFilterProgramList cachedCustomFilterPrograms; #endif +#if ENABLE(CSS_SHADERS) + m_hasCustomShaderFilter = false; +#endif + m_hasFilterThatMovesPixels = operations.hasFilterThatMovesPixels(); + if (m_hasFilterThatMovesPixels) + operations.getOutsets(m_topOutset, m_rightOutset, m_bottomOutset, m_leftOutset); m_effects.clear(); RefPtr<FilterEffect> previousEffect; @@ -237,7 +252,7 @@ void FilterEffectRenderer::build(Document* document, const FilterOperations& ope } case FilterOperation::BLUR: { BlurFilterOperation* blurOperation = static_cast<BlurFilterOperation*>(filterOperation); - float stdDeviation = blurOperation->stdDeviation().calcFloatValue(0); + float stdDeviation = floatValueForLength(blurOperation->stdDeviation(), 0); effect = FEGaussianBlur::create(this, stdDeviation, stdDeviation); break; } @@ -255,12 +270,11 @@ void FilterEffectRenderer::build(Document* document, const FilterOperations& ope CustomFilterOperation* customFilterOperation = static_cast<CustomFilterOperation*>(filterOperation); RefPtr<CustomFilterProgram> program = customFilterOperation->program(); - cachedCustomFilterPrograms.append(program); - program->addClient(this); if (program->isLoaded()) { - effect = FECustomFilter::create(this, document, program, customFilterOperation->parameters(), + effect = FECustomFilter::create(this, document->view()->root()->hostWindow(), program, customFilterOperation->parameters(), customFilterOperation->meshRows(), customFilterOperation->meshColumns(), customFilterOperation->meshBoxType(), customFilterOperation->meshType()); + m_hasCustomShaderFilter = true; } #endif break; @@ -281,51 +295,43 @@ void FilterEffectRenderer::build(Document* document, const FilterOperations& ope } } - // If we didn't make a real filter, create a null-op (FEMerge with one input). + // If we didn't make any effects, tell our caller we are not valid if (!previousEffect) - m_effects.append(FEMerge::create(this)); + return false; m_effects.first()->inputEffects().append(m_sourceGraphic); setMaxEffectRects(m_sourceDrawingRegion); -#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) - removeCustomFilterClients(); - m_cachedCustomFilterPrograms.swap(cachedCustomFilterPrograms); -#endif + return true; } -void FilterEffectRenderer::updateBackingStore(const FloatRect& filterRect) +bool FilterEffectRenderer::updateBackingStoreRect(const FloatRect& filterRect) { - if (!filterRect.isZero()) { + if (!filterRect.isZero() && isFilterSizeValid(filterRect)) { FloatRect currentSourceRect = sourceImageRect(); - if (filterRect != currentSourceRect) + if (filterRect != currentSourceRect) { setSourceImageRect(filterRect); + return true; + } } + return false; } -#if ENABLE(CSS_SHADERS) -void FilterEffectRenderer::notifyCustomFilterProgramLoaded(CustomFilterProgram*) -{ - m_observer->filterNeedsRepaint(); -} - -void FilterEffectRenderer::removeCustomFilterClients() -{ - for (CustomFilterProgramList::iterator iter = m_cachedCustomFilterPrograms.begin(), end = m_cachedCustomFilterPrograms.end(); iter != end; ++iter) - iter->get()->removeClient(this); -} -#endif - -void FilterEffectRenderer::prepare() +void FilterEffectRenderer::allocateBackingStoreIfNeeded() { // At this point the effect chain has been built, and the // source image sizes set. We just need to attach the graphic // buffer if we have not yet done so. if (!m_graphicsBufferAttached) { IntSize logicalSize(m_sourceDrawingRegion.width(), m_sourceDrawingRegion.height()); - setSourceImage(ImageBuffer::create(logicalSize, 1, ColorSpaceDeviceRGB, renderingMode())); + if (!sourceImage() || sourceImage()->logicalSize() != logicalSize) + setSourceImage(ImageBuffer::create(logicalSize, 1, ColorSpaceDeviceRGB, renderingMode())); m_graphicsBufferAttached = true; } +} + +void FilterEffectRenderer::clearIntermediateResults() +{ m_sourceGraphic->clearResult(); for (size_t i = 0; i < m_effects.size(); ++i) m_effects[i]->clearResult(); @@ -336,49 +342,95 @@ void FilterEffectRenderer::apply() lastEffect()->apply(); } +LayoutRect FilterEffectRenderer::computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect) +{ +#if ENABLE(CSS_SHADERS) + if (hasCustomShaderFilter()) { + // When we have at least a custom shader in the chain, we need to compute the whole source image, because the shader can + // reference any pixel and we cannot control that. + return filterBoxRect; + } +#endif + // The result of this function is the area in the "filterBoxRect" that needs to be repainted, so that we fully cover the "dirtyRect". + LayoutRect rectForRepaint = dirtyRect; + if (hasFilterThatMovesPixels()) { + // Note that the outsets are reversed here because we are going backwards -> we have the dirty rect and + // need to find out what is the rectangle that might influence the result inside that dirty rect. + rectForRepaint.move(-m_rightOutset, -m_bottomOutset); + rectForRepaint.expand(m_leftOutset + m_rightOutset, m_topOutset + m_bottomOutset); + } + rectForRepaint.intersect(filterBoxRect); + return rectForRepaint; +} -GraphicsContext* FilterEffectRendererHelper::beginFilterEffect(RenderLayer* renderLayer, GraphicsContext* oldContext, const LayoutRect& filterRect) +bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect) { - ASSERT(m_haveFilterEffect && renderLayer->filter()); - m_savedGraphicsContext = oldContext; + ASSERT(m_haveFilterEffect && renderLayer->filterRenderer()); m_renderLayer = renderLayer; - m_paintOffset = filterRect.location(); - - FloatRect filterSourceRect = filterRect; - filterSourceRect.setLocation(LayoutPoint()); + m_repaintRect = dirtyRect; + + FilterEffectRenderer* filter = renderLayer->filterRenderer(); + LayoutRect filterSourceRect = filter->computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect); + m_paintOffset = filterSourceRect.location(); + + if (filterSourceRect.isEmpty()) { + // The dirty rect is not in view, just bail out. + m_haveFilterEffect = false; + return false; + } - FilterEffectRenderer* filter = renderLayer->filter(); - filter->updateBackingStore(filterSourceRect); - filter->prepare(); + bool hasUpdatedBackingStore = filter->updateBackingStoreRect(filterSourceRect); + if (filter->hasFilterThatMovesPixels()) { + if (hasUpdatedBackingStore) + m_repaintRect = filterSourceRect; + else { + m_repaintRect.unite(layerRepaintRect); + m_repaintRect.intersect(filterSourceRect); + } + } + return true; +} + +GraphicsContext* FilterEffectRendererHelper::beginFilterEffect(GraphicsContext* oldContext) +{ + ASSERT(m_renderLayer); + FilterEffectRenderer* filter = m_renderLayer->filterRenderer(); + filter->allocateBackingStoreIfNeeded(); // Paint into the context that represents the SourceGraphic of the filter. GraphicsContext* sourceGraphicsContext = filter->inputContext(); - if (!sourceGraphicsContext) { - // Could not allocate a new graphics context. Disable the filters and continue. + if (!sourceGraphicsContext || !isFilterSizeValid(filter->filterRegion())) { + // Disable the filters and continue. m_haveFilterEffect = false; - return m_savedGraphicsContext; + return oldContext; } + m_savedGraphicsContext = oldContext; + + // Translate the context so that the contents of the layer is captuterd in the offscreen memory buffer. sourceGraphicsContext->save(); - sourceGraphicsContext->translate(-filterRect.x(), -filterRect.y()); - sourceGraphicsContext->clearRect(filterRect); + sourceGraphicsContext->translate(-m_paintOffset.x(), -m_paintOffset.y()); + sourceGraphicsContext->clearRect(m_repaintRect); + sourceGraphicsContext->clip(m_repaintRect); return sourceGraphicsContext; } GraphicsContext* FilterEffectRendererHelper::applyFilterEffect() { - ASSERT(m_haveFilterEffect && m_renderLayer->filter()); - FilterEffectRenderer* filter = m_renderLayer->filter(); - filter->apply(); - + ASSERT(m_haveFilterEffect && m_renderLayer->filterRenderer()); + FilterEffectRenderer* filter = m_renderLayer->filterRenderer(); filter->inputContext()->restore(); + + filter->apply(); // Get the filtered output and draw it in place. - IntRect destRect = filter->outputRect(); + LayoutRect destRect = filter->outputRect(); destRect.move(m_paintOffset.x(), m_paintOffset.y()); - m_savedGraphicsContext->drawImageBuffer(filter->output(), m_renderLayer->renderer()->style()->colorSpace(), destRect, CompositeSourceOver); + m_savedGraphicsContext->drawImageBuffer(filter->output(), m_renderLayer->renderer()->style()->colorSpace(), pixelSnappedIntRect(destRect), CompositeSourceOver); + + filter->clearIntermediateResults(); return m_savedGraphicsContext; } diff --git a/Source/WebCore/rendering/FilterEffectRenderer.h b/Source/WebCore/rendering/FilterEffectRenderer.h index b0105f248..c6266f628 100644 --- a/Source/WebCore/rendering/FilterEffectRenderer.h +++ b/Source/WebCore/rendering/FilterEffectRenderer.h @@ -41,17 +41,12 @@ #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> -#if ENABLE(CSS_SHADERS) -#include "CustomFilterProgramClient.h" -#endif - namespace WebCore { typedef Vector<RefPtr<FilterEffect> > FilterEffectList; class CachedShader; class CustomFilterProgram; class Document; -class FilterEffectObserver; class GraphicsContext; class RenderLayer; @@ -67,26 +62,26 @@ public: bool haveFilterEffect() const { return m_haveFilterEffect; } bool hasStartedFilterEffect() const { return m_savedGraphicsContext; } - GraphicsContext* beginFilterEffect(RenderLayer*, GraphicsContext* oldContext, const LayoutRect& filterRect); + bool prepareFilterEffect(RenderLayer*, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect); + GraphicsContext* beginFilterEffect(GraphicsContext* oldContext); GraphicsContext* applyFilterEffect(); + const LayoutRect& repaintRect() const { return m_repaintRect; } private: GraphicsContext* m_savedGraphicsContext; RenderLayer* m_renderLayer; LayoutPoint m_paintOffset; + LayoutRect m_repaintRect; bool m_haveFilterEffect; }; class FilterEffectRenderer : public Filter -#if ENABLE(CSS_SHADERS) - , public CustomFilterProgramClient -#endif { WTF_MAKE_FAST_ALLOCATED; public: - static PassRefPtr<FilterEffectRenderer> create(FilterEffectObserver* observer) + static PassRefPtr<FilterEffectRenderer> create() { - return adoptRef(new FilterEffectRenderer(observer)); + return adoptRef(new FilterEffectRenderer()); } virtual void setSourceImageRect(const FloatRect& sourceImageRect) @@ -104,21 +99,21 @@ public: GraphicsContext* inputContext(); ImageBuffer* output() const { return lastEffect()->asImageBuffer(); } - void build(Document*, const FilterOperations&); - void updateBackingStore(const FloatRect& filterRect); - void prepare(); + bool build(Document*, const FilterOperations&); + bool updateBackingStoreRect(const FloatRect& filterRect); + void allocateBackingStoreIfNeeded(); + void clearIntermediateResults(); void apply(); IntRect outputRect() const { return lastEffect()->hasResult() ? lastEffect()->requestedRegionOfInputImageData(IntRect(m_filterRegion)) : IntRect(); } -private: + bool hasFilterThatMovesPixels() const { return m_hasFilterThatMovesPixels; } + LayoutRect computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect); + #if ENABLE(CSS_SHADERS) - // Implementation of the CustomFilterProgramClient interface. - virtual void notifyCustomFilterProgramLoaded(CustomFilterProgram*); - - void removeCustomFilterClients(); + bool hasCustomShaderFilter() const { return m_hasCustomShaderFilter; } #endif - +private: void setMaxEffectRects(const FloatRect& effectRect) { for (size_t i = 0; i < m_effects.size(); ++i) { @@ -133,7 +128,7 @@ private: return 0; } - FilterEffectRenderer(FilterEffectObserver*); + FilterEffectRenderer(); virtual ~FilterEffectRenderer(); FloatRect m_sourceDrawingRegion; @@ -141,14 +136,17 @@ private: FilterEffectList m_effects; RefPtr<SourceGraphic> m_sourceGraphic; - FilterEffectObserver* m_observer; // No need for a strong references here. It owns us. -#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) - typedef Vector<RefPtr<CustomFilterProgram> > CustomFilterProgramList; - CustomFilterProgramList m_cachedCustomFilterPrograms; -#endif + int m_topOutset; + int m_rightOutset; + int m_bottomOutset; + int m_leftOutset; bool m_graphicsBufferAttached; + bool m_hasFilterThatMovesPixels; +#if ENABLE(CSS_SHADERS) + bool m_hasCustomShaderFilter; +#endif }; } // namespace WebCore diff --git a/Source/WebCore/rendering/FixedTableLayout.cpp b/Source/WebCore/rendering/FixedTableLayout.cpp index fe97c636f..187557ed1 100644 --- a/Source/WebCore/rendering/FixedTableLayout.cpp +++ b/Source/WebCore/rendering/FixedTableLayout.cpp @@ -77,65 +77,68 @@ FixedTableLayout::FixedTableLayout(RenderTable* table) { } +static RenderObject* nextCol(RenderObject* child) +{ + // If child is a colgroup, the next col is the colgroup's first child col. + if (RenderObject* next = child->firstChild()) + return next; + // Otherwise it's the next col along. + if (RenderObject* next = child->nextSibling()) + return next; + // Failing that, the child is the last col in a colgroup, so the next col is the next col/colgroup after its colgroup. + if (child->parent()->isTableCol()) + return child->parent()->nextSibling(); + return 0; +} + int FixedTableLayout::calcWidthArray(int) { int usedWidth = 0; // iterate over all <col> elements - RenderObject* child = m_table->firstChild(); unsigned nEffCols = m_table->numEffCols(); m_width.resize(nEffCols); m_width.fill(Length(Auto)); unsigned currentEffectiveColumn = 0; - Length grpWidth; - while (child && child->isTableCol()) { + for (RenderObject* child = m_table->firstChild();child && child->isTableCol(); child = nextCol(child)) { + + // Width specified by column-groups does not affect column width in fixed layout tables RenderTableCol* col = toRenderTableCol(child); - if (col->firstChild()) - grpWidth = col->style()->logicalWidth(); - else { - Length w = col->style()->logicalWidth(); - if (w.isAuto()) - w = grpWidth; - int effWidth = 0; - if (w.isFixed() && w.value() > 0) - effWidth = w.value(); - - unsigned span = col->span(); - while (span) { - unsigned spanInCurrentEffectiveColumn; - if (currentEffectiveColumn >= nEffCols) { - m_table->appendColumn(span); + col->computePreferredLogicalWidths(); + + if (col->isTableColGroup()) + continue; + + Length colStyleLogicalWidth = col->style()->logicalWidth(); + int effectiveColWidth = 0; + if (colStyleLogicalWidth.isFixed() && colStyleLogicalWidth.value() > 0) + effectiveColWidth = colStyleLogicalWidth.value(); + + unsigned span = col->span(); + while (span) { + unsigned spanInCurrentEffectiveColumn; + if (currentEffectiveColumn >= nEffCols) { + m_table->appendColumn(span); + nEffCols++; + m_width.append(Length()); + spanInCurrentEffectiveColumn = span; + } else { + if (span < m_table->spanOfEffCol(currentEffectiveColumn)) { + m_table->splitColumn(currentEffectiveColumn, span); nEffCols++; m_width.append(Length()); - spanInCurrentEffectiveColumn = span; - } else { - if (span < m_table->spanOfEffCol(currentEffectiveColumn)) { - m_table->splitColumn(currentEffectiveColumn, span); - nEffCols++; - m_width.append(Length()); - } - spanInCurrentEffectiveColumn = m_table->spanOfEffCol(currentEffectiveColumn); } - if ((w.isFixed() || w.isPercent()) && w.isPositive()) { - m_width[currentEffectiveColumn] = w; - m_width[currentEffectiveColumn] *= spanInCurrentEffectiveColumn; - usedWidth += effWidth * spanInCurrentEffectiveColumn; - } - span -= spanInCurrentEffectiveColumn; - currentEffectiveColumn++; + spanInCurrentEffectiveColumn = m_table->spanOfEffCol(currentEffectiveColumn); } + if ((colStyleLogicalWidth.isFixed() || colStyleLogicalWidth.isPercent()) && colStyleLogicalWidth.isPositive()) { + m_width[currentEffectiveColumn] = colStyleLogicalWidth; + m_width[currentEffectiveColumn] *= spanInCurrentEffectiveColumn; + usedWidth += effectiveColWidth * spanInCurrentEffectiveColumn; + } + span -= spanInCurrentEffectiveColumn; + currentEffectiveColumn++; } - col->computePreferredLogicalWidths(); - - RenderObject* next = child->firstChild(); - if (!next) - next = child->nextSibling(); - if (!next && child->parent()->isTableCol()) { - next = child->parent()->nextSibling(); - grpWidth = Length(); - } - child = next; } // Iterate over the first row in case some are unspecified. @@ -143,7 +146,7 @@ int FixedTableLayout::calcWidthArray(int) if (section) { unsigned cCol = 0; RenderObject* firstRow = section->firstChild(); - child = firstRow->firstChild(); + RenderObject* child = firstRow->firstChild(); while (child) { if (child->isTableCell()) { RenderTableCell* cell = toRenderTableCell(child); @@ -152,9 +155,11 @@ int FixedTableLayout::calcWidthArray(int) Length w = cell->styleOrColLogicalWidth(); unsigned span = cell->colSpan(); - int effWidth = 0; - if (w.isFixed() && w.isPositive()) - effWidth = w.value(); + int effectiveColWidth = 0; + if (w.isFixed() && w.isPositive()) { + w.setValue(w.value() + cell->borderAndPaddingLogicalWidth()); + effectiveColWidth = w.value(); + } unsigned usedSpan = 0; unsigned i = 0; @@ -164,7 +169,7 @@ int FixedTableLayout::calcWidthArray(int) if (m_width[cCol + i].isAuto() && w.type() != Auto) { m_width[cCol + i] = w; m_width[cCol + i] *= eSpan / span; - usedWidth += effWidth * eSpan / span; + usedWidth += effectiveColWidth * eSpan / span; } usedSpan += eSpan; i++; @@ -241,7 +246,7 @@ void FixedTableLayout::layout() calcWidth[i] = m_width[i].value(); totalFixedWidth += calcWidth[i]; } else if (m_width[i].isPercent()) { - calcWidth[i] = m_width[i].calcValue(tableLogicalWidth); + calcWidth[i] = valueForLength(m_width[i], tableLogicalWidth); totalPercentWidth += calcWidth[i]; totalPercent += m_width[i].percent(); } else if (m_width[i].isAuto()) { diff --git a/Source/WebCore/rendering/FlowThreadController.cpp b/Source/WebCore/rendering/FlowThreadController.cpp new file mode 100644 index 000000000..cf2207ffe --- /dev/null +++ b/Source/WebCore/rendering/FlowThreadController.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include "FlowThreadController.h" + +#include "RenderFlowThread.h" +#include "RenderNamedFlowThread.h" +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +PassOwnPtr<FlowThreadController> FlowThreadController::create(RenderView* view) +{ + return adoptPtr(new FlowThreadController(view)); +} + +FlowThreadController::FlowThreadController(RenderView* view) + : m_view(view) + , m_currentRenderFlowThread(0) + , m_isRenderNamedFlowThreadOrderDirty(false) +{ +} + +FlowThreadController::~FlowThreadController() +{ +} + +RenderNamedFlowThread* FlowThreadController::ensureRenderFlowThreadWithName(const AtomicString& name) +{ + if (!m_renderNamedFlowThreadList) + m_renderNamedFlowThreadList = adoptPtr(new RenderNamedFlowThreadList()); + else { + for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { + RenderNamedFlowThread* flowRenderer = *iter; + if (flowRenderer->flowThreadName() == name) + return flowRenderer; + } + } + + RenderNamedFlowThread* flowRenderer = new (m_view->renderArena()) RenderNamedFlowThread(m_view->document(), name); + flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(m_view->style())); + m_renderNamedFlowThreadList->add(flowRenderer); + + // Keep the flow renderer as a child of RenderView. + m_view->addChild(flowRenderer); + + setIsRenderNamedFlowThreadOrderDirty(true); + + return flowRenderer; +} + +void FlowThreadController::layoutRenderNamedFlowThreads() +{ + ASSERT(m_renderNamedFlowThreadList); + + if (isRenderNamedFlowThreadOrderDirty()) { + // Arrange the thread list according to dependencies. + RenderNamedFlowThreadList sortedList; + for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { + RenderNamedFlowThread* flowRenderer = *iter; + if (sortedList.contains(flowRenderer)) + continue; + flowRenderer->pushDependencies(sortedList); + sortedList.add(flowRenderer); + } + m_renderNamedFlowThreadList->swap(sortedList); + setIsRenderNamedFlowThreadOrderDirty(false); + } + + for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { + RenderNamedFlowThread* flowRenderer = *iter; + flowRenderer->layoutIfNeeded(); + } +} + +void FlowThreadController::registerNamedFlowContentNode(Node* contentNode, RenderNamedFlowThread* namedFlow) +{ + ASSERT(contentNode && contentNode->isElementNode()); + ASSERT(namedFlow); + ASSERT(!m_mapNamedFlowContentNodes.contains(contentNode)); + ASSERT(!namedFlow->hasContentNode(contentNode)); + m_mapNamedFlowContentNodes.add(contentNode, namedFlow); + namedFlow->registerNamedFlowContentNode(contentNode); +} + +void FlowThreadController::unregisterNamedFlowContentNode(Node* contentNode) +{ + ASSERT(contentNode && contentNode->isElementNode()); + HashMap<Node*, RenderNamedFlowThread*>::iterator it = m_mapNamedFlowContentNodes.find(contentNode); + ASSERT(it != m_mapNamedFlowContentNodes.end()); + ASSERT(it->second); + ASSERT(it->second->hasContentNode(contentNode)); + it->second->unregisterNamedFlowContentNode(contentNode); + m_mapNamedFlowContentNodes.remove(contentNode); +} + +} // namespace WebCore diff --git a/Source/WebCore/rendering/FlowThreadController.h b/Source/WebCore/rendering/FlowThreadController.h new file mode 100644 index 000000000..0c317692f --- /dev/null +++ b/Source/WebCore/rendering/FlowThreadController.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef FlowThreadController_h +#define FlowThreadController_h + +#include "RenderView.h" +#include <wtf/ListHashSet.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class RenderFlowThread; +class RenderNamedFlowThread; + +typedef ListHashSet<RenderNamedFlowThread*> RenderNamedFlowThreadList; + +class FlowThreadController { +public: + static PassOwnPtr<FlowThreadController> create(RenderView*); + ~FlowThreadController(); + + RenderFlowThread* currentRenderFlowThread() const { return m_currentRenderFlowThread; } + void setCurrentRenderFlowThread(RenderFlowThread* flowThread) { m_currentRenderFlowThread = flowThread; } + + bool isRenderNamedFlowThreadOrderDirty() const { return m_isRenderNamedFlowThreadOrderDirty; } + void setIsRenderNamedFlowThreadOrderDirty(bool dirty) + { + m_isRenderNamedFlowThreadOrderDirty = dirty; + if (dirty) + m_view->setNeedsLayout(true); + } + + RenderNamedFlowThread* ensureRenderFlowThreadWithName(const AtomicString&); + const RenderNamedFlowThreadList* renderNamedFlowThreadList() const { return m_renderNamedFlowThreadList.get(); } + bool hasRenderNamedFlowThreads() const { return m_renderNamedFlowThreadList && !m_renderNamedFlowThreadList->isEmpty(); } + void layoutRenderNamedFlowThreads(); + + void registerNamedFlowContentNode(Node*, RenderNamedFlowThread*); + void unregisterNamedFlowContentNode(Node*); + +protected: + FlowThreadController(RenderView*); + +private: + RenderView* m_view; + RenderFlowThread* m_currentRenderFlowThread; + bool m_isRenderNamedFlowThreadOrderDirty; + OwnPtr<RenderNamedFlowThreadList> m_renderNamedFlowThreadList; + // maps a content node to its render flow thread. + HashMap<Node*, RenderNamedFlowThread*> m_mapNamedFlowContentNodes; +}; + +} + +#endif diff --git a/Source/WebCore/rendering/HitTestResult.cpp b/Source/WebCore/rendering/HitTestResult.cpp index dc987c802..c19f1222f 100644 --- a/Source/WebCore/rendering/HitTestResult.cpp +++ b/Source/WebCore/rendering/HitTestResult.cpp @@ -54,6 +54,7 @@ HitTestResult::HitTestResult() , m_rightPadding(0) , m_bottomPadding(0) , m_leftPadding(0) + , m_shadowContentFilterPolicy(DoNotAllowShadowContent) , m_region(0) { } @@ -66,17 +67,19 @@ HitTestResult::HitTestResult(const LayoutPoint& point) , m_rightPadding(0) , m_bottomPadding(0) , m_leftPadding(0) + , m_shadowContentFilterPolicy(DoNotAllowShadowContent) , m_region(0) { } -HitTestResult::HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) +HitTestResult::HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, ShadowContentFilterPolicy allowShadowContent) : m_point(centerPoint) , m_isOverWidget(false) , m_topPadding(topPadding) , m_rightPadding(rightPadding) , m_bottomPadding(bottomPadding) , m_leftPadding(leftPadding) + , m_shadowContentFilterPolicy(allowShadowContent) , m_region(0) { // If all padding values passed in are zero then it is not a rect based hit test. @@ -95,6 +98,7 @@ HitTestResult::HitTestResult(const HitTestResult& other) , m_innerURLElement(other.URLElement()) , m_scrollbar(other.scrollbar()) , m_isOverWidget(other.isOverWidget()) + , m_shadowContentFilterPolicy(other.shadowContentFilterPolicy()) , m_region(other.region()) { // Only copy the padding and NodeSet in case of rect hit test. @@ -134,7 +138,8 @@ HitTestResult& HitTestResult::operator=(const HitTestResult& other) m_topPadding = m_rightPadding = m_bottomPadding = m_leftPadding = 0; m_rectBasedTestResult = adoptPtr(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0); - + m_shadowContentFilterPolicy = other.shadowContentFilterPolicy(); + m_region = other.m_region; return *this; @@ -572,7 +577,9 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const LayoutPoint& if (!node) return true; - node = node->shadowAncestorNode(); + if (m_shadowContentFilterPolicy == DoNotAllowShadowContent) + node = node->shadowAncestorNode(); + mutableRectBasedTestResult().add(node); if (node->renderer()->isInline()) { @@ -603,7 +610,9 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const LayoutPoint& if (!node) return true; - node = node->shadowAncestorNode(); + if (m_shadowContentFilterPolicy == DoNotAllowShadowContent) + node = node->shadowAncestorNode(); + mutableRectBasedTestResult().add(node); if (node->renderer()->isInline()) { @@ -643,16 +652,16 @@ void HitTestResult::append(const HitTestResult& other) } } -LayoutRect HitTestResult::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) +IntRect HitTestResult::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) { - LayoutPoint actualPoint(point); - actualPoint -= LayoutSize(leftPadding, topPadding); + IntPoint actualPoint(roundedIntPoint(point)); + actualPoint -= IntSize(leftPadding, topPadding); IntSize actualPadding(leftPadding + rightPadding, topPadding + bottomPadding); // As IntRect is left inclusive and right exclusive (seeing IntRect::contains(x, y)), adding "1". actualPadding += IntSize(1, 1); - return LayoutRect(actualPoint, actualPadding); + return IntRect(actualPoint, actualPadding); } const HitTestResult::NodeSet& HitTestResult::rectBasedTestResult() const diff --git a/Source/WebCore/rendering/HitTestResult.h b/Source/WebCore/rendering/HitTestResult.h index 152278c4d..e919472b2 100644 --- a/Source/WebCore/rendering/HitTestResult.h +++ b/Source/WebCore/rendering/HitTestResult.h @@ -42,6 +42,8 @@ class Node; class RenderRegion; class Scrollbar; +enum ShadowContentFilterPolicy { DoNotAllowShadowContent, AllowShadowContent }; + class HitTestResult { public: typedef ListHashSet<RefPtr<Node> > NodeSet; @@ -49,7 +51,7 @@ public: HitTestResult(); HitTestResult(const LayoutPoint&); // Pass non-negative padding values to perform a rect-based hit test. - HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding); + HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, ShadowContentFilterPolicy); HitTestResult(const HitTestResult&); ~HitTestResult(); HitTestResult& operator=(const HitTestResult&); @@ -68,6 +70,8 @@ public: void setToNonShadowAncestor(); + ShadowContentFilterPolicy shadowContentFilterPolicy() const { return m_shadowContentFilterPolicy; } + void setInnerNode(Node*); void setInnerNonSharedNode(Node*); void setPoint(const LayoutPoint& p) { m_point = p; } @@ -108,8 +112,8 @@ public: // Rect-based hit test related methods. bool isRectBasedTest() const { return m_isRectBased; } - LayoutRect rectForPoint(const LayoutPoint&) const; - static LayoutRect rectForPoint(const LayoutPoint&, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding); + IntRect rectForPoint(const LayoutPoint&) const; + static IntRect rectForPoint(const LayoutPoint&, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding); int topPadding() const { return m_topPadding; } int rightPadding() const { return m_rightPadding; } int bottomPadding() const { return m_bottomPadding; } @@ -146,6 +150,7 @@ private: int m_rightPadding; int m_bottomPadding; int m_leftPadding; + ShadowContentFilterPolicy m_shadowContentFilterPolicy; RenderRegion* m_region; // The region we're inside. @@ -157,7 +162,7 @@ private: // y = p.y() - topPadding // width = leftPadding + rightPadding + 1 // height = topPadding + bottomPadding + 1 -inline LayoutRect HitTestResult::rectForPoint(const LayoutPoint& point) const +inline IntRect HitTestResult::rectForPoint(const LayoutPoint& point) const { return rectForPoint(point, m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding); } diff --git a/Source/WebCore/rendering/HitTestingTransformState.cpp b/Source/WebCore/rendering/HitTestingTransformState.cpp index cb1e1d6cb..4934a7b4f 100644 --- a/Source/WebCore/rendering/HitTestingTransformState.cpp +++ b/Source/WebCore/rendering/HitTestingTransformState.cpp @@ -73,7 +73,7 @@ FloatQuad HitTestingTransformState::mappedQuad() const return m_accumulatedTransform.inverse().projectQuad(m_lastPlanarQuad); } -IntRect HitTestingTransformState::boundsOfMappedQuad() const +LayoutRect HitTestingTransformState::boundsOfMappedQuad() const { return m_accumulatedTransform.inverse().clampedBoundsOfProjectedQuad(m_lastPlanarQuad); } diff --git a/Source/WebCore/rendering/HitTestingTransformState.h b/Source/WebCore/rendering/HitTestingTransformState.h index 6aea66c63..2439dff78 100644 --- a/Source/WebCore/rendering/HitTestingTransformState.h +++ b/Source/WebCore/rendering/HitTestingTransformState.h @@ -58,7 +58,7 @@ public: FloatPoint mappedPoint() const; FloatQuad mappedQuad() const; - IntRect boundsOfMappedQuad() const; + LayoutRect boundsOfMappedQuad() const; void flatten(); FloatPoint m_lastPlanarPoint; diff --git a/Source/WebCore/rendering/InlineBox.cpp b/Source/WebCore/rendering/InlineBox.cpp index 7eceba404..957e0f0cb 100644 --- a/Source/WebCore/rendering/InlineBox.cpp +++ b/Source/WebCore/rendering/InlineBox.cpp @@ -37,22 +37,18 @@ using namespace std; namespace WebCore { -#if !COMPILER(MSVC) -// FIXME: Figure out why this doesn't work on MSVC. class SameSizeAsInlineBox { virtual ~SameSizeAsInlineBox() { } void* a[4]; FloatPoint b; float c; - uint32_t d : 31; - bool e : 1; + uint32_t d : 32; #ifndef NDEBUG bool f; #endif }; COMPILE_ASSERT(sizeof(InlineBox) == sizeof(SameSizeAsInlineBox), InlineBox_size_guard); -#endif #ifndef NDEBUG static bool inInlineBoxDetach; @@ -149,19 +145,29 @@ float InlineBox::logicalHeight() const return virtualLogicalHeight(); if (renderer()->isText()) - return m_isText ? renderer()->style(m_firstLine)->fontMetrics().height() : 0; + return m_bitfields.isText() ? renderer()->style(isFirstLineStyle())->fontMetrics().height() : 0; if (renderer()->isBox() && parent()) return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width(); ASSERT(isInlineFlowBox()); RenderBoxModelObject* flowObject = boxModelObject(); - const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics(); + const FontMetrics& fontMetrics = renderer()->style(isFirstLineStyle())->fontMetrics(); float result = fontMetrics.height(); if (parent()) result += flowObject->borderAndPaddingLogicalHeight(); return result; } +LayoutUnit InlineBox::baselinePosition(FontBaseline baselineType) const +{ + return boxModelObject()->baselinePosition(baselineType, m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); +} + +LayoutUnit InlineBox::lineHeight() const +{ + return boxModelObject()->lineHeight(m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); +} + int InlineBox::caretMinOffset() const { return m_renderer->caretMinOffset(); @@ -181,21 +187,21 @@ void InlineBox::dirtyLineBoxes() void InlineBox::deleteLine(RenderArena* arena) { - if (!m_extracted && m_renderer->isBox()) + if (!m_bitfields.extracted() && m_renderer->isBox()) toRenderBox(m_renderer)->setInlineBoxWrapper(0); destroy(arena); } void InlineBox::extractLine() { - m_extracted = true; + m_bitfields.setExtracted(true); if (m_renderer->isBox()) toRenderBox(m_renderer)->setInlineBoxWrapper(0); } void InlineBox::attachLine() { - m_extracted = false; + m_bitfields.setExtracted(false); if (m_renderer->isBox()) toRenderBox(m_renderer)->setInlineBoxWrapper(this); } @@ -262,17 +268,17 @@ RootInlineBox* InlineBox::root() bool InlineBox::nextOnLineExists() const { - if (!m_determinedIfNextOnLineExists) { - m_determinedIfNextOnLineExists = true; + if (!m_bitfields.determinedIfNextOnLineExists()) { + m_bitfields.setDeterminedIfNextOnLineExists(true); if (!parent()) - m_nextOnLineExists = false; + m_bitfields.setNextOnLineExists(false); else if (nextOnLine()) - m_nextOnLineExists = true; + m_bitfields.setNextOnLineExists(true); else - m_nextOnLineExists = parent()->nextOnLineExists(); + m_bitfields.setNextOnLineExists(parent()->nextOnLineExists()); } - return m_nextOnLineExists; + return m_bitfields.nextOnLineExists(); } InlineBox* InlineBox::nextLeafChild() const @@ -335,7 +341,7 @@ float InlineBox::placeEllipsisBox(bool, float, float, float, bool&) void InlineBox::clearKnownToHaveNoOverflow() { - m_knownToHaveNoOverflow = false; + m_bitfields.setKnownToHaveNoOverflow(false); if (parent() && parent()->knownToHaveNoOverflow()) parent()->clearKnownToHaveNoOverflow(); } diff --git a/Source/WebCore/rendering/InlineBox.h b/Source/WebCore/rendering/InlineBox.h index 196c230fd..2ed9cd40b 100644 --- a/Source/WebCore/rendering/InlineBox.h +++ b/Source/WebCore/rendering/InlineBox.h @@ -40,22 +40,6 @@ public: , m_parent(0) , m_renderer(obj) , m_logicalWidth(0) - , m_firstLine(false) - , m_constructed(false) - , m_bidiEmbeddingLevel(0) - , m_dirty(false) - , m_extracted(false) - , m_hasVirtualLogicalHeight(false) - , m_isHorizontal(true) - , m_endsWithBreak(false) - , m_hasSelectedChildrenOrCanHaveLeadingExpansion(false) - , m_knownToHaveNoOverflow(true) - , m_hasEllipsisBoxOrHyphen(false) - , m_dirOverride(false) - , m_isText(false) - , m_determinedIfNextOnLineExists(false) - , m_nextOnLineExists(false) - , m_expansion(0) #ifndef NDEBUG , m_hasBadParent(false) #endif @@ -70,22 +54,7 @@ public: , m_renderer(obj) , m_topLeft(topLeft) , m_logicalWidth(logicalWidth) - , m_firstLine(firstLine) - , m_constructed(constructed) - , m_bidiEmbeddingLevel(0) - , m_dirty(dirty) - , m_extracted(extracted) - , m_hasVirtualLogicalHeight(false) - , m_isHorizontal(isHorizontal) - , m_endsWithBreak(false) - , m_hasSelectedChildrenOrCanHaveLeadingExpansion(false) - , m_knownToHaveNoOverflow(true) - , m_hasEllipsisBoxOrHyphen(false) - , m_dirOverride(false) - , m_isText(false) - , m_determinedIfNextOnLineExists(false) - , m_nextOnLineExists(false) - , m_expansion(0) + , m_bitfields(firstLine, constructed, dirty, extracted, isHorizontal) #ifndef NDEBUG , m_hasBadParent(false) #endif @@ -121,8 +90,6 @@ public: virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom); - InlineBox* next() const { return m_next; } - // Overloaded new operator. void* operator new(size_t, RenderArena*); @@ -143,8 +110,8 @@ public: virtual const char* boxName() const; #endif - bool isText() const { return m_isText; } - void setIsText(bool b) { m_isText = b; } + bool isText() const { return m_bitfields.isText(); } + void setIsText(bool isText) { m_bitfields.setIsText(isText); } virtual bool isInlineFlowBox() const { return false; } virtual bool isInlineTextBox() const { return false; } @@ -155,16 +122,16 @@ public: virtual bool isSVGRootInlineBox() const { return false; } #endif - bool hasVirtualLogicalHeight() const { return m_hasVirtualLogicalHeight; } - void setHasVirtualLogicalHeight() { m_hasVirtualLogicalHeight = true; } + bool hasVirtualLogicalHeight() const { return m_bitfields.hasVirtualLogicalHeight(); } + void setHasVirtualLogicalHeight() { m_bitfields.setHasVirtualLogicalHeight(true); } virtual float virtualLogicalHeight() const { ASSERT_NOT_REACHED(); return 0; } - bool isHorizontal() const { return m_isHorizontal; } - void setIsHorizontal(bool horizontal) { m_isHorizontal = horizontal; } + bool isHorizontal() const { return m_bitfields.isHorizontal(); } + void setIsHorizontal(bool isHorizontal) { m_bitfields.setIsHorizontal(isHorizontal); } virtual FloatRect calculateBoundaries() const { @@ -172,13 +139,13 @@ public: return FloatRect(); } - bool isConstructed() { return m_constructed; } - virtual void setConstructed() { m_constructed = true; } + bool isConstructed() { return m_bitfields.constructed(); } + virtual void setConstructed() { m_bitfields.setConstructed(true); } - void setExtracted(bool b = true) { m_extracted = b; } + void setExtracted(bool extracted = true) { m_bitfields.setExtracted(extracted); } - void setFirstLineStyleBit(bool f) { m_firstLine = f; } - bool isFirstLineStyle() const { return m_firstLine; } + void setFirstLineStyleBit(bool firstLine) { m_bitfields.setFirstLine(firstLine); } + bool isFirstLineStyle() const { return m_bitfields.firstLine(); } void remove(); @@ -272,25 +239,25 @@ public: FloatRect logicalFrameRect() const { return isHorizontal() ? FloatRect(m_topLeft.x(), m_topLeft.y(), m_logicalWidth, logicalHeight()) : FloatRect(m_topLeft.y(), m_topLeft.x(), m_logicalWidth, logicalHeight()); } - virtual LayoutUnit baselinePosition(FontBaseline baselineType) const { return boxModelObject()->baselinePosition(baselineType, m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); } - virtual LayoutUnit lineHeight() const { return boxModelObject()->lineHeight(m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); } - + virtual LayoutUnit baselinePosition(FontBaseline baselineType) const; + virtual LayoutUnit lineHeight() const; + virtual int caretMinOffset() const; virtual int caretMaxOffset() const; - unsigned char bidiLevel() const { return m_bidiEmbeddingLevel; } - void setBidiLevel(unsigned char level) { m_bidiEmbeddingLevel = level; } - TextDirection direction() const { return m_bidiEmbeddingLevel % 2 ? RTL : LTR; } + unsigned char bidiLevel() const { return m_bitfields.bidiEmbeddingLevel(); } + void setBidiLevel(unsigned char level) { m_bitfields.setBidiEmbeddingLevel(level); } + TextDirection direction() const { return bidiLevel() % 2 ? RTL : LTR; } bool isLeftToRightDirection() const { return direction() == LTR; } int caretLeftmostOffset() const { return isLeftToRightDirection() ? caretMinOffset() : caretMaxOffset(); } int caretRightmostOffset() const { return isLeftToRightDirection() ? caretMaxOffset() : caretMinOffset(); } virtual void clearTruncation() { } - bool isDirty() const { return m_dirty; } - void markDirty(bool dirty = true) { m_dirty = dirty; } + bool isDirty() const { return m_bitfields.dirty(); } + void markDirty(bool dirty = true) { m_bitfields.setDirty(dirty); } - void dirtyLineBoxes(); + virtual void dirtyLineBoxes(); virtual RenderObject::SelectionState selectionState(); @@ -298,13 +265,15 @@ public: // visibleLeftEdge, visibleRightEdge are in the parent's coordinate system. virtual float placeEllipsisBox(bool ltr, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, bool&); +#ifndef NDEBUG void setHasBadParent(); +#endif + + int expansion() const { return m_bitfields.expansion(); } - int expansion() const { return m_expansion; } - bool visibleToHitTesting() const { return renderer()->style()->visibility() == VISIBLE && renderer()->style()->pointerEvents() != PE_NONE; } - EVerticalAlign verticalAlign() const { return renderer()->style(m_firstLine)->verticalAlign(); } + EVerticalAlign verticalAlign() const { return renderer()->style(m_bitfields.firstLine())->verticalAlign(); } // Use with caution! The type is not checked! RenderBoxModelObject* boxModelObject() const @@ -320,9 +289,12 @@ public: void flipForWritingMode(LayoutRect&); LayoutPoint flipForWritingMode(const LayoutPoint&); - bool knownToHaveNoOverflow() const { return m_knownToHaveNoOverflow; } + bool knownToHaveNoOverflow() const { return m_bitfields.knownToHaveNoOverflow(); } void clearKnownToHaveNoOverflow(); + bool dirOverride() const { return m_bitfields.dirOverride(); } + void setDirOverride(bool dirOverride) { m_bitfields.setDirOverride(dirOverride); } + private: InlineBox* m_next; // The next element on the same line as us. InlineBox* m_prev; // The previous element on the same line as us. @@ -334,37 +306,107 @@ public: FloatPoint m_topLeft; float m_logicalWidth; - - // Some of these bits are actually for subclasses and moved here to compact the structures. - - // for this class -protected: - bool m_firstLine : 1; -private: - bool m_constructed : 1; - unsigned char m_bidiEmbeddingLevel : 6; -protected: - bool m_dirty : 1; - bool m_extracted : 1; - bool m_hasVirtualLogicalHeight : 1; - bool m_isHorizontal : 1; +#define ADD_BOOLEAN_BITFIELD(name, Name) \ + private:\ + unsigned m_##name : 1;\ + public:\ + bool name() const { return m_##name; }\ + void set##Name(bool name) { m_##name = name; }\ + + class InlineBoxBitfields { + public: + InlineBoxBitfields(bool firstLine = false, bool constructed = false, bool dirty = false, bool extracted = false, bool isHorizontal = true) + : m_firstLine(firstLine) + , m_constructed(constructed) + , m_bidiEmbeddingLevel(0) + , m_dirty(dirty) + , m_extracted(extracted) + , m_hasVirtualLogicalHeight(false) + , m_isHorizontal(isHorizontal) + , m_endsWithBreak(false) + , m_hasSelectedChildrenOrCanHaveLeadingExpansion(false) + , m_knownToHaveNoOverflow(true) + , m_hasEllipsisBoxOrHyphen(false) + , m_dirOverride(false) + , m_isText(false) + , m_determinedIfNextOnLineExists(false) + , m_nextOnLineExists(false) + , m_expansion(0) + { + } + + // Some of these bits are actually for subclasses and moved here to compact the structures. + // for this class + ADD_BOOLEAN_BITFIELD(firstLine, FirstLine); + ADD_BOOLEAN_BITFIELD(constructed, Constructed); + + private: + unsigned m_bidiEmbeddingLevel : 6; // The maximium bidi level is 62: http://unicode.org/reports/tr9/#Explicit_Levels_and_Directions + + public: + unsigned char bidiEmbeddingLevel() const { return m_bidiEmbeddingLevel; } + void setBidiEmbeddingLevel(unsigned char bidiEmbeddingLevel) { m_bidiEmbeddingLevel = bidiEmbeddingLevel; } + + ADD_BOOLEAN_BITFIELD(dirty, Dirty); + ADD_BOOLEAN_BITFIELD(extracted, Extracted); + ADD_BOOLEAN_BITFIELD(hasVirtualLogicalHeight, HasVirtualLogicalHeight); + ADD_BOOLEAN_BITFIELD(isHorizontal, IsHorizontal); + // for RootInlineBox + ADD_BOOLEAN_BITFIELD(endsWithBreak, EndsWithBreak); // Whether the line ends with a <br>. + // shared between RootInlineBox and InlineTextBox + ADD_BOOLEAN_BITFIELD(hasSelectedChildrenOrCanHaveLeadingExpansion, HasSelectedChildrenOrCanHaveLeadingExpansion); + ADD_BOOLEAN_BITFIELD(knownToHaveNoOverflow, KnownToHaveNoOverflow); + ADD_BOOLEAN_BITFIELD(hasEllipsisBoxOrHyphen, HasEllipsisBoxOrHyphen); + // for InlineTextBox + ADD_BOOLEAN_BITFIELD(dirOverride, DirOverride); + ADD_BOOLEAN_BITFIELD(isText, IsText); // Whether or not this object represents text with a non-zero height. Includes non-image list markers, text boxes. + + private: + mutable unsigned m_determinedIfNextOnLineExists : 1; + + public: + bool determinedIfNextOnLineExists() const { return m_determinedIfNextOnLineExists; } + void setDeterminedIfNextOnLineExists(bool determinedIfNextOnLineExists) const { m_determinedIfNextOnLineExists = determinedIfNextOnLineExists; } + + private: + mutable unsigned m_nextOnLineExists : 1; + + public: + bool nextOnLineExists() const { return m_nextOnLineExists; } + void setNextOnLineExists(bool nextOnLineExists) const { m_nextOnLineExists = nextOnLineExists; } + + private: + signed m_expansion : 12; // for justified text + + public: + signed expansion() const { return m_expansion; } + void setExpansion(signed expansion) { m_expansion = expansion; } + }; +#undef ADD_BOOLEAN_BITFIELD - // for RootInlineBox - bool m_endsWithBreak : 1; // Whether the line ends with a <br>. - // shared between RootInlineBox and InlineTextBox - bool m_hasSelectedChildrenOrCanHaveLeadingExpansion : 1; // Whether we have any children selected (this bit will also be set if the <br> that terminates our line is selected). - bool m_knownToHaveNoOverflow : 1; - bool m_hasEllipsisBoxOrHyphen : 1; +private: + InlineBoxBitfields m_bitfields; - // for InlineTextBox -public: - bool m_dirOverride : 1; - bool m_isText : 1; // Whether or not this object represents text with a non-zero height. Includes non-image list markers, text boxes. protected: - mutable bool m_determinedIfNextOnLineExists : 1; - mutable bool m_nextOnLineExists : 1; - signed m_expansion : 12; // for justified text + // For RootInlineBox + bool endsWithBreak() const { return m_bitfields.endsWithBreak(); } + void setEndsWithBreak(bool endsWithBreak) { m_bitfields.setEndsWithBreak(endsWithBreak); } + bool hasEllipsisBox() const { return m_bitfields.hasEllipsisBoxOrHyphen(); } + bool hasSelectedChildren() const { return m_bitfields.hasSelectedChildrenOrCanHaveLeadingExpansion(); } + void setHasSelectedChildren(bool hasSelectedChildren) { m_bitfields.setHasSelectedChildrenOrCanHaveLeadingExpansion(hasSelectedChildren); } + void setHasEllipsisBox(bool hasEllipsisBox) { m_bitfields.setHasEllipsisBoxOrHyphen(hasEllipsisBox); } + + // For InlineTextBox + bool hasHyphen() const { return m_bitfields.hasEllipsisBoxOrHyphen(); } + void setHasHyphen(bool hasHyphen) { m_bitfields.setHasEllipsisBoxOrHyphen(hasHyphen); } + bool canHaveLeadingExpansion() const { return m_bitfields.hasSelectedChildrenOrCanHaveLeadingExpansion(); } + void setCanHaveLeadingExpansion(bool canHaveLeadingExpansion) { m_bitfields.setHasSelectedChildrenOrCanHaveLeadingExpansion(canHaveLeadingExpansion); } + signed expansion() { return m_bitfields.expansion(); } + void setExpansion(signed expansion) { m_bitfields.setExpansion(expansion); } + + // For InlineFlowBox and InlineTextBox + bool extracted() const { return m_bitfields.extracted(); } #ifndef NDEBUG private: @@ -378,12 +420,12 @@ inline InlineBox::~InlineBox() } #endif +#ifndef NDEBUG inline void InlineBox::setHasBadParent() { -#ifndef NDEBUG m_hasBadParent = true; -#endif } +#endif } // namespace WebCore diff --git a/Source/WebCore/rendering/InlineFlowBox.cpp b/Source/WebCore/rendering/InlineFlowBox.cpp index bf84a0a03..cbd685d69 100644 --- a/Source/WebCore/rendering/InlineFlowBox.cpp +++ b/Source/WebCore/rendering/InlineFlowBox.cpp @@ -45,6 +45,13 @@ using namespace std; namespace WebCore { +class SameSizeAsInlineFlowBox : public InlineBox { + void* pointers[5]; + uint32_t bitfields : 24; +}; + +COMPILE_ASSERT(sizeof(InlineFlowBox) == sizeof(SameSizeAsInlineFlowBox), InlineFlowBox_should_stay_small); + #ifndef NDEBUG InlineFlowBox::~InlineFlowBox() @@ -102,7 +109,7 @@ void InlineFlowBox::addToLine(InlineBox* child) child->setPrevOnLine(m_lastChild); m_lastChild = child; } - child->setFirstLineStyleBit(m_firstLine); + child->setFirstLineStyleBit(isFirstLineStyle()); child->setIsHorizontal(isHorizontal()); if (child->isText()) { if (child->renderer()->parent() == renderer()) @@ -114,8 +121,8 @@ void InlineFlowBox::addToLine(InlineBox* child) } if (descendantsHaveSameLineHeightAndBaseline() && !child->renderer()->isPositioned()) { - RenderStyle* parentStyle = renderer()->style(m_firstLine); - RenderStyle* childStyle = child->renderer()->style(m_firstLine); + RenderStyle* parentStyle = renderer()->style(isFirstLineStyle()); + RenderStyle* childStyle = child->renderer()->style(isFirstLineStyle()); bool shouldClearDescendantsHaveSameLineHeightAndBaseline = false; if (child->renderer()->isReplaced()) shouldClearDescendantsHaveSameLineHeightAndBaseline = true; @@ -152,16 +159,16 @@ void InlineFlowBox::addToLine(InlineBox* child) if (!child->renderer()->isPositioned()) { if (child->isText()) { - RenderStyle* childStyle = child->renderer()->style(m_firstLine); + RenderStyle* childStyle = child->renderer()->style(isFirstLineStyle()); if (childStyle->letterSpacing() < 0 || childStyle->textShadow() || childStyle->textEmphasisMark() != TextEmphasisMarkNone || childStyle->textStrokeWidth()) child->clearKnownToHaveNoOverflow(); } else if (child->renderer()->isReplaced()) { RenderBox* box = toRenderBox(child->renderer()); if (box->hasRenderOverflow() || box->hasSelfPaintingLayer()) child->clearKnownToHaveNoOverflow(); - } else if (!child->renderer()->isBR() && (child->renderer()->style(m_firstLine)->boxShadow() || child->boxModelObject()->hasSelfPaintingLayer() + } else if (!child->renderer()->isBR() && (child->renderer()->style(isFirstLineStyle())->boxShadow() || child->boxModelObject()->hasSelfPaintingLayer() || (child->renderer()->isListMarker() && !toRenderListMarker(child->renderer())->isInside()) - || child->renderer()->style(m_firstLine)->hasBorderImageOutsets())) + || child->renderer()->style(isFirstLineStyle())->hasBorderImageOutsets())) child->clearKnownToHaveNoOverflow(); if (knownToHaveNoOverflow() && child->isInlineFlowBox() && !toInlineFlowBox(child)->knownToHaveNoOverflow()) @@ -175,7 +182,7 @@ void InlineFlowBox::removeChild(InlineBox* child) { checkConsistency(); - if (!m_dirty) + if (!isDirty()) dirtyLineBoxes(); root()->childRemoved(child); @@ -223,7 +230,7 @@ void InlineFlowBox::removeLineBoxFromRenderObject() void InlineFlowBox::extractLine() { - if (!m_extracted) + if (!extracted()) extractLineBoxFromRenderObject(); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) child->extractLine(); @@ -236,7 +243,7 @@ void InlineFlowBox::extractLineBoxFromRenderObject() void InlineFlowBox::attachLine() { - if (m_extracted) + if (extracted()) attachLineBoxToRenderObject(); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) child->attachLine(); @@ -365,7 +372,7 @@ float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsW RenderText* rt = toRenderText(text->renderer()); if (rt->textLength()) { if (needsWordSpacing && isSpaceOrNewline(rt->characters()[text->start()])) - logicalLeft += rt->style(m_firstLine)->font().wordSpacing(); + logicalLeft += rt->style(isFirstLineStyle())->font().wordSpacing(); needsWordSpacing = !isSpaceOrNewline(rt->characters()[text->end()]); } text->setLogicalLeft(logicalLeft); @@ -424,8 +431,8 @@ bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFo if (isHorizontal()) return false; - if (renderer()->style(m_firstLine)->fontDescription().textOrientation() == TextOrientationUpright - || renderer()->style(m_firstLine)->font().primaryFont()->hasVerticalGlyphs()) + if (renderer()->style(isFirstLineStyle())->fontDescription().textOrientation() == TextOrientationUpright + || renderer()->style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs()) return true; for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { @@ -436,7 +443,7 @@ bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFo if (toInlineFlowBox(curr)->requiresIdeographicBaseline(textBoxDataMap)) return true; } else { - if (curr->renderer()->style(m_firstLine)->font().primaryFont()->hasVerticalGlyphs()) + if (curr->renderer()->style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs()) return true; const Vector<const SimpleFontData*>* usedFonts = 0; @@ -586,8 +593,10 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei { bool isRootBox = isRootInlineBox(); if (isRootBox) { - const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics(); - setLogicalTop(top + maxAscent - fontMetrics.ascent(baselineType)); + const FontMetrics& fontMetrics = renderer()->style(isFirstLineStyle())->fontMetrics(); + // RootInlineBoxes are always placed on at pixel boundaries in their logical y direction. Not doing + // so results in incorrect rendering of text decorations, most notably underlines. + setLogicalTop(roundToInt(top + maxAscent - fontMetrics.ascent(baselineType))); } LayoutUnit adjustmentForChildrenWithSameLineHeightAndBaseline = 0; @@ -626,11 +635,11 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei LayoutUnit boxHeightIncludingMargins = boxHeight; if (curr->isText() || curr->isInlineFlowBox()) { - const FontMetrics& fontMetrics = curr->renderer()->style(m_firstLine)->fontMetrics(); + const FontMetrics& fontMetrics = curr->renderer()->style(isFirstLineStyle())->fontMetrics(); newLogicalTop += curr->baselinePosition(baselineType) - fontMetrics.ascent(baselineType); if (curr->isInlineFlowBox()) { RenderBoxModelObject* boxObject = toRenderBoxModelObject(curr->renderer()); - newLogicalTop -= boxObject->style(m_firstLine)->isHorizontalWritingMode() ? boxObject->borderTop() + boxObject->paddingTop() : + newLogicalTop -= boxObject->style(isFirstLineStyle())->isHorizontalWritingMode() ? boxObject->borderTop() + boxObject->paddingTop() : boxObject->borderRight() + boxObject->paddingRight(); } newLogicalTopIncludingMargins = newLogicalTop; @@ -657,17 +666,17 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei RenderRubyRun* rubyRun = toRenderRubyRun(curr->renderer()); if (RenderRubyBase* rubyBase = rubyRun->rubyBase()) { - LayoutUnit bottomRubyBaseLeading = (curr->logicalHeight() - rubyBase->logicalBottom()) + rubyBase->logicalHeight() - (rubyBase->lastRootBox() ? rubyBase->lastRootBox()->lineBottom() : zeroLayoutUnit); - LayoutUnit topRubyBaseLeading = rubyBase->logicalTop() + (rubyBase->firstRootBox() ? rubyBase->firstRootBox()->lineTop() : zeroLayoutUnit); + LayoutUnit bottomRubyBaseLeading = (curr->logicalHeight() - rubyBase->logicalBottom()) + rubyBase->logicalHeight() - (rubyBase->lastRootBox() ? rubyBase->lastRootBox()->lineBottom() : ZERO_LAYOUT_UNIT); + LayoutUnit topRubyBaseLeading = rubyBase->logicalTop() + (rubyBase->firstRootBox() ? rubyBase->firstRootBox()->lineTop() : ZERO_LAYOUT_UNIT); newLogicalTop += !renderer()->style()->isFlippedLinesWritingMode() ? topRubyBaseLeading : bottomRubyBaseLeading; boxHeight -= (topRubyBaseLeading + bottomRubyBaseLeading); } } if (curr->isInlineTextBox()) { TextEmphasisPosition emphasisMarkPosition; - if (toInlineTextBox(curr)->getEmphasisMarkPosition(curr->renderer()->style(m_firstLine), emphasisMarkPosition)) { + if (toInlineTextBox(curr)->getEmphasisMarkPosition(curr->renderer()->style(isFirstLineStyle()), emphasisMarkPosition)) { bool emphasisMarkIsOver = emphasisMarkPosition == TextEmphasisPositionOver; - if (emphasisMarkIsOver != curr->renderer()->style(m_firstLine)->isFlippedLinesWritingMode()) + if (emphasisMarkIsOver != curr->renderer()->style(isFirstLineStyle())->isFlippedLinesWritingMode()) hasAnnotationsBefore = true; else hasAnnotationsAfter = true; @@ -734,7 +743,7 @@ inline void InlineFlowBox::addBoxShadowVisualOverflow(LayoutRect& logicalVisualO if (!parent()) return; - RenderStyle* style = renderer()->style(m_firstLine); + RenderStyle* style = renderer()->style(isFirstLineStyle()); if (!style->boxShadow()) return; @@ -767,7 +776,7 @@ inline void InlineFlowBox::addBorderOutsetVisualOverflow(LayoutRect& logicalVisu if (!parent()) return; - RenderStyle* style = renderer()->style(m_firstLine); + RenderStyle* style = renderer()->style(isFirstLineStyle()); if (!style->hasBorderImageOutsets()) return; @@ -787,8 +796,8 @@ inline void InlineFlowBox::addBorderOutsetVisualOverflow(LayoutRect& logicalVisu LayoutUnit borderOutsetLogicalRight; style->getBorderImageInlineDirectionOutsets(borderOutsetLogicalLeft, borderOutsetLogicalRight); - LayoutUnit outsetLogicalLeft = includeLogicalLeftEdge() ? borderOutsetLogicalLeft : zeroLayoutUnit; - LayoutUnit outsetLogicalRight = includeLogicalRightEdge() ? borderOutsetLogicalRight : zeroLayoutUnit; + LayoutUnit outsetLogicalLeft = includeLogicalLeftEdge() ? borderOutsetLogicalLeft : ZERO_LAYOUT_UNIT; + LayoutUnit outsetLogicalRight = includeLogicalRightEdge() ? borderOutsetLogicalRight : ZERO_LAYOUT_UNIT; LayoutUnit logicalLeftVisualOverflow = min(pixelSnappedLogicalLeft() - outsetLogicalLeft, logicalVisualOverflow.x()); LayoutUnit logicalRightVisualOverflow = max(pixelSnappedLogicalRight() + outsetLogicalRight, logicalVisualOverflow.maxX()); @@ -802,7 +811,7 @@ inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, Glyp if (textBox->knownToHaveNoOverflow()) return; - RenderStyle* style = textBox->renderer()->style(m_firstLine); + RenderStyle* style = textBox->renderer()->style(isFirstLineStyle()); GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(textBox); GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->second.second; @@ -1116,8 +1125,8 @@ void InlineFlowBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, c for (InlineFlowBox* curr = this; curr; curr = curr->prevLineBox()) totalLogicalWidth += curr->logicalWidth(); } - LayoutUnit stripX = rect.x() - (isHorizontal() ? logicalOffsetOnLine : zeroLayoutUnit); - LayoutUnit stripY = rect.y() - (isHorizontal() ? zeroLayoutUnit : logicalOffsetOnLine); + LayoutUnit stripX = rect.x() - (isHorizontal() ? logicalOffsetOnLine : ZERO_LAYOUT_UNIT); + LayoutUnit stripY = rect.y() - (isHorizontal() ? ZERO_LAYOUT_UNIT : logicalOffsetOnLine); LayoutUnit stripWidth = isHorizontal() ? totalLogicalWidth : static_cast<LayoutUnit>(width()); LayoutUnit stripHeight = isHorizontal() ? static_cast<LayoutUnit>(height()) : totalLogicalWidth; @@ -1208,8 +1217,8 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& // You can use p::first-line to specify a background. If so, the root line boxes for // a line may actually have to paint a background. - RenderStyle* styleToUse = renderer()->style(m_firstLine); - if ((!parent() && m_firstLine && styleToUse != renderer()->style()) || (parent() && renderer()->hasBoxDecorations())) { + RenderStyle* styleToUse = renderer()->style(isFirstLineStyle()); + if ((!parent() && isFirstLineStyle() && styleToUse != renderer()->style()) || (parent() && renderer()->hasBoxDecorations())) { LayoutRect paintRect = LayoutRect(adjustedPaintoffset, frameRect.size()); // Shadow comes first and is behind the background and border. if (!boxModelObject()->boxShadowShouldBeAppliedToBackground(BackgroundBleedNone, this)) @@ -1231,7 +1240,7 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& // The simple case is where we either have no border image or we are the only box for this object. In those // cases only a single call to draw is required. if (!hasBorderImage || (!prevLineBox() && !nextLineBox())) - boxModelObject()->paintBorder(paintInfo, paintRect, renderer()->style(), BackgroundBleedNone, includeLogicalLeftEdge(), includeLogicalRightEdge()); + boxModelObject()->paintBorder(paintInfo, paintRect, renderer()->style(isFirstLineStyle()), BackgroundBleedNone, includeLogicalLeftEdge(), includeLogicalRightEdge()); else { // We have a border image that spans multiple lines. // We need to adjust tx and ty by the width of all previous lines. @@ -1247,15 +1256,15 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& LayoutUnit totalLogicalWidth = logicalOffsetOnLine; for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox()) totalLogicalWidth += curr->logicalWidth(); - LayoutUnit stripX = adjustedPaintoffset.x() - (isHorizontal() ? logicalOffsetOnLine : zeroLayoutUnit); - LayoutUnit stripY = adjustedPaintoffset.y() - (isHorizontal() ? zeroLayoutUnit : logicalOffsetOnLine); + LayoutUnit stripX = adjustedPaintoffset.x() - (isHorizontal() ? logicalOffsetOnLine : ZERO_LAYOUT_UNIT); + LayoutUnit stripY = adjustedPaintoffset.y() - (isHorizontal() ? ZERO_LAYOUT_UNIT : logicalOffsetOnLine); LayoutUnit stripWidth = isHorizontal() ? totalLogicalWidth : frameRect.width(); LayoutUnit stripHeight = isHorizontal() ? frameRect.height() : totalLogicalWidth; LayoutRect clipRect = clipRectForNinePieceImageStrip(this, borderImage, paintRect); GraphicsContextStateSaver stateSaver(*context); context->clip(clipRect); - boxModelObject()->paintBorder(paintInfo, LayoutRect(stripX, stripY, stripWidth, stripHeight), renderer()->style()); + boxModelObject()->paintBorder(paintInfo, LayoutRect(stripX, stripY, stripWidth, stripHeight), renderer()->style(isFirstLineStyle())); } } } @@ -1282,8 +1291,9 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffs // Figure out if we need to push a transparency layer to render our mask. bool pushTransparencyLayer = false; bool compositedMask = renderer()->hasLayer() && boxModelObject()->layer()->hasCompositedMask(); + bool flattenCompositingLayers = renderer()->view()->frameView() && renderer()->view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers; CompositeOperator compositeOp = CompositeSourceOver; - if (!compositedMask) { + if (!compositedMask || flattenCompositingLayers) { if ((maskBoxImage && renderer()->style()->maskLayers()->hasImage()) || renderer()->style()->maskLayers()->next()) pushTransparencyLayer = true; @@ -1318,8 +1328,8 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffs LayoutUnit totalLogicalWidth = logicalOffsetOnLine; for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox()) totalLogicalWidth += curr->logicalWidth(); - LayoutUnit stripX = adjustedPaintOffset.x() - (isHorizontal() ? logicalOffsetOnLine : zeroLayoutUnit); - LayoutUnit stripY = adjustedPaintOffset.y() - (isHorizontal() ? zeroLayoutUnit : logicalOffsetOnLine); + LayoutUnit stripX = adjustedPaintOffset.x() - (isHorizontal() ? logicalOffsetOnLine : ZERO_LAYOUT_UNIT); + LayoutUnit stripY = adjustedPaintOffset.y() - (isHorizontal() ? ZERO_LAYOUT_UNIT : logicalOffsetOnLine); LayoutUnit stripWidth = isHorizontal() ? totalLogicalWidth : frameRect.width(); LayoutUnit stripHeight = isHorizontal() ? frameRect.height() : totalLogicalWidth; @@ -1416,7 +1426,7 @@ LayoutUnit InlineFlowBox::computeOverAnnotationAdjustment(LayoutUnit allowedPosi continue; if (!rubyRun->style()->isFlippedLinesWritingMode()) { - LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : zeroLayoutUnit); + LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : ZERO_LAYOUT_UNIT); if (topOfFirstRubyTextLine >= 0) continue; topOfFirstRubyTextLine += curr->logicalTop(); @@ -1431,7 +1441,7 @@ LayoutUnit InlineFlowBox::computeOverAnnotationAdjustment(LayoutUnit allowedPosi } if (curr->isInlineTextBox()) { - RenderStyle* style = curr->renderer()->style(m_firstLine); + RenderStyle* style = curr->renderer()->style(isFirstLineStyle()); TextEmphasisPosition emphasisMarkPosition; if (style->textEmphasisMark() != TextEmphasisMarkNone && toInlineTextBox(curr)->getEmphasisMarkPosition(style, emphasisMarkPosition) && emphasisMarkPosition == TextEmphasisPositionOver) { if (!style->isFlippedLinesWritingMode()) { @@ -1458,7 +1468,7 @@ LayoutUnit InlineFlowBox::computeUnderAnnotationAdjustment(LayoutUnit allowedPos result = max(result, toInlineFlowBox(curr)->computeUnderAnnotationAdjustment(allowedPosition)); if (curr->isInlineTextBox()) { - RenderStyle* style = curr->renderer()->style(m_firstLine); + RenderStyle* style = curr->renderer()->style(isFirstLineStyle()); if (style->textEmphasisMark() != TextEmphasisMarkNone && style->textEmphasisPosition() == TextEmphasisPositionUnder) { if (!style->isFlippedLinesWritingMode()) { LayoutUnit bottomOfEmphasisMark = curr->logicalBottom() + style->font().emphasisMarkHeight(style->textEmphasisMarkString()); diff --git a/Source/WebCore/rendering/InlineFlowBox.h b/Source/WebCore/rendering/InlineFlowBox.h index a81af717b..bfdf87efd 100644 --- a/Source/WebCore/rendering/InlineFlowBox.h +++ b/Source/WebCore/rendering/InlineFlowBox.h @@ -88,7 +88,7 @@ public: virtual void setConstructed() { InlineBox::setConstructed(); - for (InlineBox* child = firstChild(); child; child = child->next()) + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) child->setConstructed(); } @@ -137,13 +137,13 @@ public: { if (!includeLogicalLeftEdge()) return 0; - return isHorizontal() ? renderer()->style()->borderLeftWidth() : renderer()->style()->borderTopWidth(); + return isHorizontal() ? renderer()->style(isFirstLineStyle())->borderLeftWidth() : renderer()->style(isFirstLineStyle())->borderTopWidth(); } int borderLogicalRight() const { if (!includeLogicalRightEdge()) return 0; - return isHorizontal() ? renderer()->style()->borderRightWidth() : renderer()->style()->borderBottomWidth(); + return isHorizontal() ? renderer()->style(isFirstLineStyle())->borderRightWidth() : renderer()->style(isFirstLineStyle())->borderBottomWidth(); } int paddingLogicalLeft() const { @@ -297,20 +297,22 @@ protected: InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject - bool m_includeLogicalLeftEdge : 1; - bool m_includeLogicalRightEdge : 1; - bool m_hasTextChildren : 1; - bool m_hasTextDescendants : 1; - bool m_descendantsHaveSameLineHeightAndBaseline : 1; +private: + unsigned m_includeLogicalLeftEdge : 1; + unsigned m_includeLogicalRightEdge : 1; + unsigned m_hasTextChildren : 1; + unsigned m_hasTextDescendants : 1; + unsigned m_descendantsHaveSameLineHeightAndBaseline : 1; +protected: // The following members are only used by RootInlineBox but moved here to keep the bits packed. // Whether or not this line uses alphabetic or ideographic baselines by default. unsigned m_baselineType : 1; // FontBaseline // If the line contains any ruby runs, then this will be true. - bool m_hasAnnotationsBefore : 1; - bool m_hasAnnotationsAfter : 1; + unsigned m_hasAnnotationsBefore : 1; + unsigned m_hasAnnotationsAfter : 1; unsigned m_lineBreakBidiStatusEor : 5; // WTF::Unicode::Direction unsigned m_lineBreakBidiStatusLastStrong : 5; // WTF::Unicode::Direction @@ -320,7 +322,7 @@ protected: #ifndef NDEBUG private: - bool m_hasBadChildList; + unsigned m_hasBadChildList : 1; #endif }; diff --git a/Source/WebCore/rendering/InlineTextBox.cpp b/Source/WebCore/rendering/InlineTextBox.cpp index 639d6bad6..d6ed33287 100644 --- a/Source/WebCore/rendering/InlineTextBox.cpp +++ b/Source/WebCore/rendering/InlineTextBox.cpp @@ -59,21 +59,21 @@ static InlineTextBoxOverflowMap* gTextBoxesWithOverflow; void InlineTextBox::destroy(RenderArena* arena) { - if (!m_knownToHaveNoOverflow && gTextBoxesWithOverflow) + if (!knownToHaveNoOverflow() && gTextBoxesWithOverflow) gTextBoxesWithOverflow->remove(this); InlineBox::destroy(arena); } LayoutRect InlineTextBox::logicalOverflowRect() const { - if (m_knownToHaveNoOverflow || !gTextBoxesWithOverflow) + if (knownToHaveNoOverflow() || !gTextBoxesWithOverflow) return enclosingIntRect(logicalFrameRect()); return gTextBoxesWithOverflow->get(this); } void InlineTextBox::setLogicalOverflowRect(const LayoutRect& rect) { - ASSERT(!m_knownToHaveNoOverflow); + ASSERT(!knownToHaveNoOverflow()); if (!gTextBoxesWithOverflow) gTextBoxesWithOverflow = new InlineTextBoxOverflowMap; gTextBoxesWithOverflow->add(this, rect); @@ -85,7 +85,7 @@ LayoutUnit InlineTextBox::baselinePosition(FontBaseline baselineType) const return 0; if (parent()->renderer() == renderer()->parent()) return parent()->baselinePosition(baselineType); - return toRenderBoxModelObject(renderer()->parent())->baselinePosition(baselineType, m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); + return toRenderBoxModelObject(renderer()->parent())->baselinePosition(baselineType, isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); } LayoutUnit InlineTextBox::lineHeight() const @@ -93,10 +93,10 @@ LayoutUnit InlineTextBox::lineHeight() const if (!isText() || !renderer()->parent()) return 0; if (m_renderer->isBR()) - return toRenderBR(m_renderer)->lineHeight(m_firstLine); + return toRenderBR(m_renderer)->lineHeight(isFirstLineStyle()); if (parent()->renderer() == renderer()->parent()) return parent()->lineHeight(); - return toRenderBoxModelObject(renderer()->parent())->lineHeight(m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); + return toRenderBoxModelObject(renderer()->parent())->lineHeight(isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); } LayoutUnit InlineTextBox::selectionTop() @@ -174,20 +174,20 @@ static void adjustCharactersAndLengthForHyphen(BufferForAppendingHyphen& charact length += hyphenString.length(); } -IntRect InlineTextBox::localSelectionRect(int startPos, int endPos) +LayoutRect InlineTextBox::localSelectionRect(int startPos, int endPos) { int sPos = max(startPos - m_start, 0); int ePos = min(endPos - m_start, (int)m_len); if (sPos > ePos) - return IntRect(); + return LayoutRect(); FontCachePurgePreventer fontCachePurgePreventer; RenderText* textObj = textRenderer(); - int selTop = selectionTop(); - int selHeight = selectionHeight(); - RenderStyle* styleToUse = textObj->style(m_firstLine); + LayoutUnit selTop = selectionTop(); + LayoutUnit selHeight = selectionHeight(); + RenderStyle* styleToUse = textObj->style(isFirstLineStyle()); const Font& font = styleToUse->font(); BufferForAppendingHyphen charactersWithHyphen; @@ -196,19 +196,19 @@ IntRect InlineTextBox::localSelectionRect(int startPos, int endPos) if (respectHyphen) endPos = textRun.length(); - IntRect r = enclosingIntRect(font.selectionRectForText(textRun, FloatPoint(logicalLeft(), selTop), selHeight, sPos, ePos)); + LayoutRect r = enclosingIntRect(font.selectionRectForText(textRun, FloatPoint(logicalLeft(), selTop), selHeight, sPos, ePos)); - int logicalWidth = r.width(); + LayoutUnit logicalWidth = r.width(); if (r.x() > logicalRight()) logicalWidth = 0; else if (r.maxX() > logicalRight()) logicalWidth = logicalRight() - r.x(); - IntPoint topPoint = isHorizontal() ? IntPoint(r.x(), selTop) : IntPoint(selTop, r.x()); - int width = isHorizontal() ? logicalWidth : selHeight; - int height = isHorizontal() ? selHeight : logicalWidth; + LayoutPoint topPoint = isHorizontal() ? LayoutPoint(r.x(), selTop) : LayoutPoint(selTop, r.x()); + LayoutUnit width = isHorizontal() ? logicalWidth : selHeight; + LayoutUnit height = isHorizontal() ? selHeight : logicalWidth; - return IntRect(topPoint, IntSize(width, height)); + return LayoutRect(topPoint, LayoutSize(width, height)); } void InlineTextBox::deleteLine(RenderArena* arena) @@ -219,7 +219,7 @@ void InlineTextBox::deleteLine(RenderArena* arena) void InlineTextBox::extractLine() { - if (m_extracted) + if (extracted()) return; toRenderText(renderer())->extractTextBox(this); @@ -227,7 +227,7 @@ void InlineTextBox::extractLine() void InlineTextBox::attachLine() { - if (!m_extracted) + if (!extracted()) return; toRenderText(renderer())->attachTextBox(this); @@ -283,7 +283,7 @@ float InlineTextBox::placeEllipsisBox(bool flowIsLTR, float visibleLeftEdge, flo // If we got here that means that we were only partially truncated and we need to return the pixel offset at which // to place the ellipsis. - float widthOfVisibleText = toRenderText(renderer())->width(m_start, offset, textPos(), m_firstLine); + float widthOfVisibleText = toRenderText(renderer())->width(m_start, offset, textPos(), isFirstLineStyle()); // The ellipsis needs to be placed just after the last visible character. // Where "after" is defined by the flow directionality, not the inline @@ -483,7 +483,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit paintEnd = isHorizontal() ? paintInfo.rect.maxX() : paintInfo.rect.maxY(); LayoutUnit paintStart = isHorizontal() ? paintInfo.rect.x() : paintInfo.rect.y(); - LayoutPoint adjustedPaintOffset = paintOffset; + LayoutPoint adjustedPaintOffset = roundedIntPoint(paintOffset); if (logicalStart >= paintEnd || logicalStart + logicalExtent <= paintStart) return; @@ -506,7 +506,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, // farther to the right. // NOTE: WebKit's behavior differs from that of IE which appears to just overlay the ellipsis on top of the // truncated string i.e. |Hello|CBA| -> |...lo|CBA| - LayoutUnit widthOfVisibleText = toRenderText(renderer())->width(m_start, m_truncation, textPos(), m_firstLine); + LayoutUnit widthOfVisibleText = toRenderText(renderer())->width(m_start, m_truncation, textPos(), isFirstLineStyle()); LayoutUnit widthOfHiddenText = m_logicalWidth - widthOfVisibleText; // FIXME: The hit testing logic also needs to take this translation into account. LayoutSize truncationOffset(isLeftToRightDirection() ? widthOfHiddenText : -widthOfHiddenText, 0); @@ -516,7 +516,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, GraphicsContext* context = paintInfo.context; - RenderStyle* styleToUse = renderer()->style(m_firstLine); + RenderStyle* styleToUse = renderer()->style(isFirstLineStyle()); adjustedPaintOffset.move(0, styleToUse->isHorizontalWritingMode() ? 0 : -logicalHeight()); @@ -841,8 +841,12 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& b if (respectHyphen) ePos = textRun.length(); - int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop(); - int selHeight = selectionHeight(); + LayoutUnit selectionBottom = root()->selectionBottom(); + LayoutUnit selectionTop = root()->selectionTopAdjustedForPrecedingBlock(); + + int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom - logicalBottom() : logicalTop() - selectionTop; + int selHeight = max<LayoutUnit>(0, selectionBottom - selectionTop); + FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); FloatRect clipRect(localOrigin, FloatSize(m_logicalWidth, selHeight)); @@ -904,7 +908,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& float width = m_logicalWidth; if (m_truncation != cNoTruncation) { - width = toRenderText(renderer())->width(m_start, m_truncation, textPos(), m_firstLine); + width = toRenderText(renderer())->width(m_start, m_truncation, textPos(), isFirstLineStyle()); if (!isLeftToRightDirection()) localOrigin.move(m_logicalWidth - width, 0); } @@ -919,7 +923,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& bool linesAreOpaque = !isPrinting && (!(deco & UNDERLINE) || underline.alpha() == 255) && (!(deco & OVERLINE) || overline.alpha() == 255) && (!(deco & LINE_THROUGH) || linethrough.alpha() == 255); - RenderStyle* styleToUse = renderer()->style(m_firstLine); + RenderStyle* styleToUse = renderer()->style(isFirstLineStyle()); int baseline = styleToUse->fontMetrics().ascent(); bool setClip = false; @@ -983,22 +987,24 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& context->clearShadow(); } -static GraphicsContext::TextCheckingLineStyle textCheckingLineStyleForMarkerType(DocumentMarker::MarkerType markerType) +static GraphicsContext::DocumentMarkerLineStyle lineStyleForMarkerType(DocumentMarker::MarkerType markerType) { switch (markerType) { case DocumentMarker::Spelling: - return GraphicsContext::TextCheckingSpellingLineStyle; + return GraphicsContext::DocumentMarkerSpellingLineStyle; case DocumentMarker::Grammar: - return GraphicsContext::TextCheckingGrammarLineStyle; + return GraphicsContext::DocumentMarkerGrammarLineStyle; case DocumentMarker::CorrectionIndicator: - return GraphicsContext::TextCheckingReplacementLineStyle; + return GraphicsContext::DocumentMarkerAutocorrectionReplacementLineStyle; + case DocumentMarker::DictationAlternatives: + return GraphicsContext::DocumentMarkerDictationAlternativesLineStyle; default: ASSERT_NOT_REACHED(); - return GraphicsContext::TextCheckingSpellingLineStyle; + return GraphicsContext::DocumentMarkerSpellingLineStyle; } } -void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const FloatPoint& boxOrigin, DocumentMarker* marker, RenderStyle* style, const Font& font, bool grammar) +void InlineTextBox::paintDocumentMarker(GraphicsContext* pt, const FloatPoint& boxOrigin, DocumentMarker* marker, RenderStyle* style, const Font& font, bool grammar) { // Never print spelling/grammar markers (5327887) if (textRenderer()->document()->printing()) @@ -1053,7 +1059,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const Floa // So, we generally place the underline at the bottom of the text, but in larger fonts that's not so good so // we pin to two pixels under the baseline. int lineThickness = cMisspellingLineThickness; - int baseline = renderer()->style(m_firstLine)->fontMetrics().ascent(); + int baseline = renderer()->style(isFirstLineStyle())->fontMetrics().ascent(); int descent = logicalHeight() - baseline; int underlineOffset; if (descent <= (2 + lineThickness)) { @@ -1063,7 +1069,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const Floa // In larger fonts, though, place the underline up near the baseline to prevent a big gap. underlineOffset = baseline + 2; } - pt->drawLineForTextChecking(FloatPoint(boxOrigin.x() + start, boxOrigin.y() + underlineOffset), width, textCheckingLineStyleForMarkerType(marker->type())); + pt->drawLineForDocumentMarker(FloatPoint(boxOrigin.x() + start, boxOrigin.y() + underlineOffset), width, lineStyleForMarkerType(marker->type())); } void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const FloatPoint& boxOrigin, DocumentMarker* marker, RenderStyle* style, const Font& font) @@ -1130,6 +1136,7 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const FloatPoint& case DocumentMarker::Spelling: case DocumentMarker::CorrectionIndicator: case DocumentMarker::Replacement: + case DocumentMarker::DictationAlternatives: if (background) continue; break; @@ -1153,17 +1160,16 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const FloatPoint& // marker intersects this run. Paint it. switch (marker->type()) { case DocumentMarker::Spelling: - paintSpellingOrGrammarMarker(pt, boxOrigin, marker, style, font, false); + case DocumentMarker::CorrectionIndicator: + case DocumentMarker::DictationAlternatives: + paintDocumentMarker(pt, boxOrigin, marker, style, font, false); break; case DocumentMarker::Grammar: - paintSpellingOrGrammarMarker(pt, boxOrigin, marker, style, font, true); + paintDocumentMarker(pt, boxOrigin, marker, style, font, true); break; case DocumentMarker::TextMatch: paintTextMatchMarker(pt, boxOrigin, marker, style, font); break; - case DocumentMarker::CorrectionIndicator: - paintSpellingOrGrammarMarker(pt, boxOrigin, marker, style, font, false); - break; case DocumentMarker::Replacement: computeRectForReplacementMarker(marker, style, font); break; @@ -1187,7 +1193,7 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, const FloatP if (paintStart <= underline.startOffset) { paintStart = underline.startOffset; useWholeWidth = false; - start = toRenderText(renderer())->width(m_start, paintStart - m_start, textPos(), m_firstLine); + start = toRenderText(renderer())->width(m_start, paintStart - m_start, textPos(), isFirstLineStyle()); } if (paintEnd != underline.endOffset) { // end points at the last char, not past it paintEnd = min(paintEnd, (unsigned)underline.endOffset); @@ -1198,14 +1204,14 @@ void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, const FloatP useWholeWidth = false; } if (!useWholeWidth) { - width = toRenderText(renderer())->width(paintStart, paintEnd - paintStart, textPos() + start, m_firstLine); + width = toRenderText(renderer())->width(paintStart, paintEnd - paintStart, textPos() + start, isFirstLineStyle()); } // Thick marked text underlines are 2px thick as long as there is room for the 2px line under the baseline. // All other marked text underlines are 1px thick. // If there's not enough space the underline will touch or overlap characters. int lineThickness = 1; - int baseline = renderer()->style(m_firstLine)->fontMetrics().ascent(); + int baseline = renderer()->style(isFirstLineStyle())->fontMetrics().ascent(); if (underline.thick && logicalHeight() - baseline >= 2) lineThickness = 2; @@ -1251,7 +1257,7 @@ int InlineTextBox::offsetForPosition(float lineOffset, bool includePartialGlyphs FontCachePurgePreventer fontCachePurgePreventer; RenderText* text = toRenderText(renderer()); - RenderStyle* style = text->style(m_firstLine); + RenderStyle* style = text->style(isFirstLineStyle()); const Font& font = style->font(); return font.offsetForPosition(constructTextRun(style, font), lineOffset - logicalLeft(), includePartialGlyphs); } @@ -1267,7 +1273,7 @@ float InlineTextBox::positionForOffset(int offset) const FontCachePurgePreventer fontCachePurgePreventer; RenderText* text = toRenderText(renderer()); - RenderStyle* styleToUse = text->style(m_firstLine); + RenderStyle* styleToUse = text->style(isFirstLineStyle()); ASSERT(styleToUse); const Font& font = styleToUse->font(); int from = !isLeftToRightDirection() ? offset - m_start : 0; @@ -1325,7 +1331,7 @@ TextRun InlineTextBox::constructTextRun(RenderStyle* style, const Font& font, co ASSERT(maximumLength >= length); - TextRun run(characters, length, textRenderer->allowTabs(), textPos(), expansion(), expansionBehavior(), direction(), m_dirOverride || style->rtlOrdering() == VisualOrder); + TextRun run(characters, length, textRenderer->allowTabs(), textPos(), expansion(), expansionBehavior(), direction(), dirOverride() || style->rtlOrdering() == VisualOrder, !textRenderer->canUseSimpleFontCodePath()); if (textRunNeedsRenderingContext(font)) run.setRenderingContext(SVGTextRunRenderingContext::create(textRenderer)); diff --git a/Source/WebCore/rendering/InlineTextBox.h b/Source/WebCore/rendering/InlineTextBox.h index e59660e3f..a9bde74f0 100644 --- a/Source/WebCore/rendering/InlineTextBox.h +++ b/Source/WebCore/rendering/InlineTextBox.h @@ -75,11 +75,10 @@ public: unsigned short truncation() { return m_truncation; } - bool hasHyphen() const { return m_hasEllipsisBoxOrHyphen; } - void setHasHyphen(bool hasHyphen) { m_hasEllipsisBoxOrHyphen = hasHyphen; } - - bool canHaveLeadingExpansion() const { return m_hasSelectedChildrenOrCanHaveLeadingExpansion; } - void setCanHaveLeadingExpansion(bool canHaveLeadingExpansion) { m_hasSelectedChildrenOrCanHaveLeadingExpansion = canHaveLeadingExpansion; } + using InlineBox::hasHyphen; + using InlineBox::setHasHyphen; + using InlineBox::canHaveLeadingExpansion; + using InlineBox::setCanHaveLeadingExpansion; static inline bool compareByStart(const InlineTextBox* first, const InlineTextBox* second) { return first->start() < second->start(); } @@ -110,7 +109,7 @@ private: public: virtual FloatRect calculateBoundaries() const { return FloatRect(x(), y(), width(), height()); } - virtual IntRect localSelectionRect(int startPos, int endPos); + virtual LayoutRect localSelectionRect(int startPos, int endPos); bool isSelected(int startPos, int endPos) const; void selectionStartEnd(int& sPos, int& ePos); @@ -136,7 +135,12 @@ private: public: virtual bool isLineBreak() const; - void setExpansion(int expansion) { m_logicalWidth -= m_expansion; m_expansion = expansion; m_logicalWidth += m_expansion; } + void setExpansion(int newExpansion) + { + m_logicalWidth -= expansion(); + InlineBox::setExpansion(newExpansion); + m_logicalWidth += newExpansion; + } private: virtual bool isInlineTextBox() const { return true; } @@ -178,14 +182,14 @@ protected: private: void paintDecoration(GraphicsContext*, const FloatPoint& boxOrigin, int decoration, const ShadowData*); void paintSelection(GraphicsContext*, const FloatPoint& boxOrigin, RenderStyle*, const Font&); - void paintSpellingOrGrammarMarker(GraphicsContext*, const FloatPoint& boxOrigin, DocumentMarker*, RenderStyle*, const Font&, bool grammar); + void paintDocumentMarker(GraphicsContext*, const FloatPoint& boxOrigin, DocumentMarker*, RenderStyle*, const Font&, bool grammar); void paintTextMatchMarker(GraphicsContext*, const FloatPoint& boxOrigin, DocumentMarker*, RenderStyle*, const Font&); void computeRectForReplacementMarker(DocumentMarker*, RenderStyle*, const Font&); TextRun::ExpansionBehavior expansionBehavior() const { return (canHaveLeadingExpansion() ? TextRun::AllowLeadingExpansion : TextRun::ForbidLeadingExpansion) - | (m_expansion && nextLeafChild() ? TextRun::AllowTrailingExpansion : TextRun::ForbidTrailingExpansion); + | (expansion() && nextLeafChild() ? TextRun::AllowTrailingExpansion : TextRun::ForbidTrailingExpansion); } }; diff --git a/Source/WebCore/rendering/LayoutRepainter.cpp b/Source/WebCore/rendering/LayoutRepainter.cpp index 80b659df6..205ad4ab8 100644 --- a/Source/WebCore/rendering/LayoutRepainter.cpp +++ b/Source/WebCore/rendering/LayoutRepainter.cpp @@ -30,14 +30,14 @@ namespace WebCore { -LayoutRepainter::LayoutRepainter(RenderObject& object, bool checkForRepaint, const IntRect* oldBounds) +LayoutRepainter::LayoutRepainter(RenderObject& object, bool checkForRepaint) : m_object(object) , m_repaintContainer(0) , m_checkForRepaint(checkForRepaint) { if (m_checkForRepaint) { m_repaintContainer = m_object.containerForRepaint(); - m_oldBounds = oldBounds ? *oldBounds : m_object.clippedOverflowRectForRepaint(m_repaintContainer); + m_oldBounds = m_object.clippedOverflowRectForRepaint(m_repaintContainer); m_oldOutlineBox = m_object.outlineBoundsForRepaint(m_repaintContainer); } } diff --git a/Source/WebCore/rendering/LayoutRepainter.h b/Source/WebCore/rendering/LayoutRepainter.h index 60aabc736..57400faeb 100644 --- a/Source/WebCore/rendering/LayoutRepainter.h +++ b/Source/WebCore/rendering/LayoutRepainter.h @@ -35,7 +35,7 @@ class RenderBoxModelObject; class LayoutRepainter { public: - LayoutRepainter(RenderObject&, bool checkForRepaint, const IntRect* oldBounds = 0); + LayoutRepainter(RenderObject&, bool checkForRepaint); bool checkForRepaint() const { return m_checkForRepaint; } @@ -45,8 +45,9 @@ public: private: RenderObject& m_object; RenderBoxModelObject* m_repaintContainer; - IntRect m_oldBounds; - IntRect m_oldOutlineBox; + // We store these values as LayoutRects, but the final invalidations will be pixel snapped + LayoutRect m_oldBounds; + LayoutRect m_oldOutlineBox; bool m_checkForRepaint; }; diff --git a/Source/WebCore/rendering/LayoutTypes.h b/Source/WebCore/rendering/LayoutTypes.h index 2041ee597..dd56ad710 100644 --- a/Source/WebCore/rendering/LayoutTypes.h +++ b/Source/WebCore/rendering/LayoutTypes.h @@ -37,97 +37,102 @@ #define LayoutTypes_h #include "FloatRect.h" +#include "FractionalLayoutRect.h" +#include "FractionalLayoutUnit.h" #include "IntRect.h" -#include <wtf/UnusedParam.h> + +#include <wtf/MathExtras.h> namespace WebCore { -typedef int LayoutUnit; -typedef IntPoint LayoutPoint; -typedef IntSize LayoutSize; -typedef IntRect LayoutRect; +typedef FractionalLayoutUnit LayoutUnit; +typedef FractionalLayoutPoint LayoutPoint; +typedef FractionalLayoutSize LayoutSize; +typedef FractionalLayoutRect LayoutRect; -const LayoutUnit zeroLayoutUnit = 0; +#define MAX_LAYOUT_UNIT LayoutUnit::max() +#define MIN_LAYOUT_UNIT LayoutUnit::min() +#define ZERO_LAYOUT_UNIT LayoutUnit(0) -inline LayoutRect enclosingLayoutRect(const FloatRect& rect) +inline FractionalLayoutRect enclosingLayoutRect(const FloatRect& rect) { return enclosingIntRect(rect); } -inline IntRect pixelSnappedIntRect(const LayoutRect& rect) +inline LayoutSize roundedLayoutSize(const FloatSize& s) { - return rect; +#if ENABLE(SUBPIXEL_LAYOUT) + return FractionalLayoutSize(s); +#else + return roundedIntSize(s); +#endif } inline IntRect pixelSnappedIntRect(LayoutUnit left, LayoutUnit top, LayoutUnit width, LayoutUnit height) { - return IntRect(left, top, width, height); -} - -inline IntRect pixelSnappedIntRect(const LayoutPoint& location, const LayoutSize& size) -{ - return IntRect(location, size); + return IntRect(left.round(), top.round(), snapSizeToPixel(width, left), snapSizeToPixel(height, top)); } inline IntRect pixelSnappedIntRectFromEdges(LayoutUnit left, LayoutUnit top, LayoutUnit right, LayoutUnit bottom) { - return IntRect(left, top, right - left, bottom - top); -} - -inline int snapSizeToPixel(LayoutUnit size, LayoutUnit location) -{ - UNUSED_PARAM(location); - return size; -} - -inline IntSize roundedIntSize(const LayoutSize& s) -{ - return s; -} - -inline LayoutSize roundedLayoutSize(const FloatSize& s) -{ - return roundedIntSize(s); -} - -inline IntPoint roundedIntPoint(const LayoutPoint& p) -{ - return p; + return IntRect(left.round(), top.round(), snapSizeToPixel(right - left, left), snapSizeToPixel(bottom - top, top)); } inline LayoutPoint roundedLayoutPoint(const FloatPoint& p) { +#if ENABLE(SUBPIXEL_LAYOUT) + return FractionalLayoutPoint(p); +#else return roundedIntPoint(p); +#endif } inline LayoutPoint flooredLayoutPoint(const FloatPoint& p) { - return flooredIntPoint(p); + return LayoutPoint(p.x(), p.y()); } inline LayoutPoint flooredLayoutPoint(const FloatSize& s) { - return flooredIntPoint(s); + return LayoutPoint(s.width(), s.height()); } inline LayoutSize flooredLayoutSize(const FloatPoint& p) { - return LayoutSize(static_cast<int>(p.x()), static_cast<int>(p.y())); + return LayoutSize(p.x(), p.y()); } inline int roundToInt(LayoutUnit value) { - return value; + return value.round(); +} + +inline int floorToInt(LayoutUnit value) +{ + return value.toInt(); } inline LayoutUnit roundedLayoutUnit(float value) { - return lroundf(value); +#if ENABLE(SUBPIXEL_LAYOUT) + return FractionalLayoutUnit(value); +#else + return static_cast<int>(lroundf(value)); +#endif } inline LayoutUnit ceiledLayoutUnit(float value) { +#if ENABLE(SUBPIXEL_LAYOUT) + return FractionalLayoutUnit(value); +#else return ceilf(value); +#endif +} + +inline LayoutUnit absoluteValue(const LayoutUnit& value) +{ + return value.abs(); } inline LayoutSize toLayoutSize(const LayoutPoint& p) @@ -142,12 +147,22 @@ inline LayoutPoint toLayoutPoint(const LayoutSize& p) inline LayoutUnit layoutMod(const LayoutUnit& numerator, const LayoutUnit& denominator) { - return numerator % denominator; + return numerator.toInt() % denominator.toInt(); } inline LayoutUnit clampToLayoutUnit(double value) { - return clampToInteger(value); + return clampTo<FractionalLayoutUnit>(value, FractionalLayoutUnit::min(), FractionalLayoutUnit::max()); +} + +inline IntRect pixelSnappedIntRect(LayoutPoint location, LayoutSize size) +{ + return IntRect(roundedIntPoint(location), pixelSnappedIntSize(size, location)); +} + +inline bool isIntegerValue(const LayoutUnit value) +{ + return value.floor() == value; } } // namespace WebCore diff --git a/Source/WebCore/rendering/PaintInfo.h b/Source/WebCore/rendering/PaintInfo.h index e28ba0dab..7ed743272 100644 --- a/Source/WebCore/rendering/PaintInfo.h +++ b/Source/WebCore/rendering/PaintInfo.h @@ -32,7 +32,9 @@ #include "GraphicsContext.h" #include "IntRect.h" +#include "LayoutTypes.h" #include "PaintPhase.h" +#include <limits> #include <wtf/HashMap.h> #include <wtf/ListHashSet.h> @@ -96,7 +98,7 @@ struct PaintInfo { } #endif - static IntRect infiniteRect() { return IntRect(INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX); } + static IntRect infiniteRect() { return IntRect(LayoutRect::infiniteRect()); } // FIXME: Introduce setters/getters at some point. Requires a lot of changes throughout rendering/. GraphicsContext* context; diff --git a/Source/WebCore/rendering/RenderApplet.cpp b/Source/WebCore/rendering/RenderApplet.cpp index 090ba1678..1b8b75e17 100644 --- a/Source/WebCore/rendering/RenderApplet.cpp +++ b/Source/WebCore/rendering/RenderApplet.cpp @@ -44,13 +44,13 @@ RenderApplet::~RenderApplet() { } -LayoutSize RenderApplet::intrinsicSize() const +IntSize RenderApplet::intrinsicSize() const { // FIXME: This doesn't make sense. We can't just start returning // a different size once we've created the widget and expect // layout and sizing to be correct. We should remove this and // pass the appropriate intrinsic size in the constructor. - return widget() ? LayoutSize(50, 50) : LayoutSize(150, 150); + return widget() ? IntSize(50, 50) : IntSize(150, 150); } void RenderApplet::createWidgetIfNecessary() diff --git a/Source/WebCore/rendering/RenderApplet.h b/Source/WebCore/rendering/RenderApplet.h index 9478c5b79..007902d1f 100644 --- a/Source/WebCore/rendering/RenderApplet.h +++ b/Source/WebCore/rendering/RenderApplet.h @@ -46,7 +46,7 @@ private: virtual bool isApplet() const { return true; } virtual void layout(); - virtual LayoutSize intrinsicSize() const; + virtual IntSize intrinsicSize() const; #if USE(ACCELERATED_COMPOSITING) virtual bool requiresLayer() const; diff --git a/Source/WebCore/rendering/RenderArena.cpp b/Source/WebCore/rendering/RenderArena.cpp index 6c4c5dc15..b01f65ddd 100644 --- a/Source/WebCore/rendering/RenderArena.cpp +++ b/Source/WebCore/rendering/RenderArena.cpp @@ -110,7 +110,9 @@ void* RenderArena::allocate(size_t size) if (!result) { // Allocate a new chunk from the arena - ARENA_ALLOCATE(result, &m_pool, size); + unsigned bytesAllocated = 0; + ARENA_ALLOCATE(result, &m_pool, size, &bytesAllocated); + m_totalAllocated += bytesAllocated; } return result; diff --git a/Source/WebCore/rendering/RenderArena.h b/Source/WebCore/rendering/RenderArena.h index 9150e7135..0b64e1877 100644 --- a/Source/WebCore/rendering/RenderArena.h +++ b/Source/WebCore/rendering/RenderArena.h @@ -54,6 +54,7 @@ public: void free(size_t, void*); size_t totalRenderArenaSize() const { return m_totalSize; } + size_t totalRenderArenaAllocatedBytes() const { return m_totalAllocated; } private: // Underlying arena pool @@ -64,6 +65,7 @@ private: void* m_recyclers[gMaxRecycledSize >> 2]; size_t m_totalSize; + size_t m_totalAllocated; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderBR.cpp b/Source/WebCore/rendering/RenderBR.cpp index ca14e45be..d80393614 100644 --- a/Source/WebCore/rendering/RenderBR.cpp +++ b/Source/WebCore/rendering/RenderBR.cpp @@ -43,11 +43,11 @@ int RenderBR::lineHeight(bool firstLine) const if (firstLine && document()->usesFirstLineRules()) { RenderStyle* s = style(firstLine); if (s != style()) - return s->computedLineHeight(); + return s->computedLineHeight(view()); } if (m_lineHeight == -1) - m_lineHeight = style()->computedLineHeight(); + m_lineHeight = style()->computedLineHeight(view()); return m_lineHeight; } diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index d87d77226..d03463b51 100755 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -45,11 +45,11 @@ #include "RenderBoxRegionInfo.h" #include "RenderCombineText.h" #include "RenderDeprecatedFlexibleBox.h" -#include "RenderFlowThread.h" #include "RenderImage.h" #include "RenderInline.h" #include "RenderLayer.h" #include "RenderMarquee.h" +#include "RenderNamedFlowThread.h" #include "RenderRegion.h" #include "RenderReplica.h" #include "RenderTableCell.h" @@ -69,6 +69,29 @@ namespace WebCore { using namespace HTMLNames; +struct SameSizeAsRenderBlock : public RenderBox { + void* pointers[3]; + RenderObjectChildList children; + RenderLineBoxList lineBoxes; + uint32_t bitfields; +}; + +COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small); + +struct SameSizeAsFloatingObject { + void* pointers[2]; + LayoutRect rect; + int paginationStrut; + uint32_t bitfields : 8; +}; + +COMPILE_ASSERT(sizeof(RenderBlock::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small); + +struct SameSizeAsMarginInfo { + uint32_t bitfields : 16; + LayoutUnit margins[2]; +}; + typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap; static ColumnInfoMap* gColumnInfoMap = 0; @@ -167,8 +190,8 @@ RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderP m_quirkContainer = block->isTableCell() || block->isBody() || blockStyle->marginBeforeCollapse() == MDISCARD || blockStyle->marginAfterCollapse() == MDISCARD; - m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : zeroLayoutUnit; - m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : zeroLayoutUnit; + m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : ZERO_LAYOUT_UNIT; + m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : ZERO_LAYOUT_UNIT; } // ------------------------------------------------------------------------------------------------------- @@ -177,10 +200,11 @@ RenderBlock::RenderBlock(Node* node) : RenderBox(node) , m_lineHeight(-1) , m_beingDestroyed(false) - , m_hasPositionedFloats(false) , m_hasMarkupTruncation(false) { setChildrenInline(true); + COMPILE_ASSERT(sizeof(RenderBlock::FloatingObject) == sizeof(SameSizeAsFloatingObject), FloatingObject_should_stay_small); + COMPILE_ASSERT(sizeof(RenderBlock::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small); } RenderBlock::~RenderBlock() @@ -481,7 +505,8 @@ void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, Render } // Split our anonymous blocks. - RenderObject* newBeforeChild = splitAnonymousBlocksAroundChild(beforeChild); + RenderObject* newBeforeChild = splitAnonymousBoxesAroundChild(beforeChild); + // Create a new anonymous box of the appropriate type. RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock(); @@ -681,94 +706,6 @@ void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, post->setNeedsLayoutAndPrefWidthsRecalc(); } -RenderObject* RenderBlock::splitAnonymousBlocksAroundChild(RenderObject* beforeChild) -{ - if (beforeChild->isTablePart()) - beforeChild = splitTablePartsAroundChild(beforeChild); - - while (beforeChild->parent() != this) { - RenderBlock* blockToSplit = toRenderBlock(beforeChild->parent()); - if (blockToSplit->firstChild() != beforeChild) { - // We have to split the parentBlock into two blocks. - RenderBlock* post = createAnonymousBlockWithSameTypeAs(blockToSplit); - post->setChildrenInline(blockToSplit->childrenInline()); - RenderBlock* parentBlock = toRenderBlock(blockToSplit->parent()); - parentBlock->children()->insertChildNode(parentBlock, post, blockToSplit->nextSibling()); - blockToSplit->moveChildrenTo(post, beforeChild, 0, blockToSplit->hasLayer()); - post->setNeedsLayoutAndPrefWidthsRecalc(); - blockToSplit->setNeedsLayoutAndPrefWidthsRecalc(); - beforeChild = post; - } else - beforeChild = blockToSplit; - } - return beforeChild; -} - -static void markTableForSectionAndCellRecalculation(RenderObject* child) -{ - RenderObject* curr = child; - while (!curr->isTable()) { - if (curr->isTableSection()) - toRenderTableSection(curr)->setNeedsCellRecalc(); - curr = curr->parent(); - } - - RenderTable* table = toRenderTable(curr); - table->setNeedsSectionRecalc(); - table->setNeedsLayoutAndPrefWidthsRecalc(); -} - -static void moveAllTableChildrenTo(RenderObject* fromTablePart, RenderTable* toTable, RenderObject* startChild) -{ - for (RenderObject* curr = startChild; curr;) { - // Need to store next sibling as we won't have access to it - // after we are removed from table. - RenderObject* next = curr->nextSibling(); - fromTablePart->removeChild(curr); - toTable->addChild(curr); - if (curr->isTableSection()) - toRenderTableSection(curr)->setNeedsCellRecalc(); - curr->setNeedsLayoutAndPrefWidthsRecalc(); - curr = next; - } - - // This marks fromTable for section and cell recalculation. - markTableForSectionAndCellRecalculation(fromTablePart); - - // startChild is now part of toTable. This marks toTable for section and cell recalculation. - markTableForSectionAndCellRecalculation(startChild); -} - -RenderObject* RenderBlock::splitTablePartsAroundChild(RenderObject* beforeChild) -{ - ASSERT(beforeChild->isTablePart()); - - while (beforeChild->parent() != this) { - RenderObject* tablePartToSplit = beforeChild->parent(); - if (!tablePartToSplit->isTablePart() && !tablePartToSplit->isTable()) - break; - if (tablePartToSplit->firstChild() != beforeChild) { - // Get our table container. - RenderObject* curr = tablePartToSplit; - while (!curr->isTable()) - curr = curr->parent(); - RenderTable* table = toRenderTable(curr); - - // Create an anonymous table container next to our table container. - RenderBlock* parentBlock = toRenderBlock(table->parent()); - RenderTable* postTable = parentBlock->createAnonymousTable(); - parentBlock->children()->insertChildNode(parentBlock, postTable, table->nextSibling()); - - // Move all the children from beforeChild to the newly created anonymous table container. - moveAllTableChildrenTo(tablePartToSplit, postTable, beforeChild); - - beforeChild = postTable; - } else - beforeChild = tablePartToSplit; - } - return beforeChild; -} - void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild) { RenderBlock* pre = 0; @@ -780,7 +717,7 @@ void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, R block->deleteLineBoxTree(); if (beforeChild && beforeChild->parent() != this) - beforeChild = splitAnonymousBlocksAroundChild(beforeChild); + beforeChild = splitAnonymousBoxesAroundChild(beforeChild); if (beforeChild != firstChild()) { pre = block->createAnonymousColumnsBlock(); @@ -868,7 +805,13 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, // If the requested beforeChild is not one of our children, then this is because // there is an anonymous container within this object that contains the beforeChild. RenderObject* beforeChildAnonymousContainer = beforeChildContainer; - if (beforeChildAnonymousContainer->isAnonymousBlock()) { + if (beforeChildAnonymousContainer->isAnonymousBlock() +#if ENABLE(FULLSCREEN_API) + // Full screen renderers and full screen placeholders act as anonymous blocks, not tables: + || beforeChildAnonymousContainer->isRenderFullScreen() + || beforeChildAnonymousContainer->isRenderFullScreenPlaceholder() +#endif + ) { // Insert the child into the anonymous block box instead of here. if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild) beforeChild->parent()->addChild(newChild, beforeChild); @@ -884,7 +827,7 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, return; } - beforeChild = splitTablePartsAroundChild(beforeChild); + beforeChild = splitAnonymousBoxesAroundChild(beforeChild); ASSERT(beforeChild->parent() == this); if (beforeChild->parent() != this) { @@ -921,12 +864,19 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after // content gets properly destroyed. + bool isFirstChild = (beforeChild == firstChild()); bool isLastChild = (beforeChild == lastChild()); if (document()->usesBeforeAfterRules()) children()->updateBeforeAfterContent(this, AFTER); - if (isLastChild && beforeChild != lastChild()) - beforeChild = 0; // We destroyed the last child, so now we need to update our insertion - // point to be 0. It's just a straight append now. + if (isLastChild && beforeChild != lastChild()) { + // We destroyed the last child, so now we need to update our insertion + // point to be 0. It's just a straight append now. + beforeChild = 0; + } else if (isFirstChild && beforeChild != firstChild()) { + // If beforeChild was the last anonymous block that collapsed, + // then we need to update its value. + beforeChild = firstChild(); + } splitFlow(beforeChild, newBox, newChild, oldContinuation); return; @@ -1063,30 +1013,6 @@ RootInlineBox* RenderBlock::createAndAppendRootInlineBox() return rootBox; } -void RenderBlock::moveChildTo(RenderBlock* toBlock, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert) -{ - ASSERT(this == child->parent()); - ASSERT(!beforeChild || toBlock == beforeChild->parent()); - if (fullRemoveInsert) { - // Takes care of adding the new child correctly if toBlock and fromBlock - // have different kind of children (block vs inline). - toBlock->addChildIgnoringContinuation(children()->removeChildNode(this, child), beforeChild); - } else - toBlock->children()->insertChildNode(toBlock, children()->removeChildNode(this, child, false), beforeChild, false); -} - -void RenderBlock::moveChildrenTo(RenderBlock* toBlock, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert) -{ - ASSERT(!beforeChild || toBlock == beforeChild->parent()); - - for (RenderObject* child = startChild; child && child != endChild; ) { - // Save our next sibling as moveChildTo will clear it. - RenderObject* nextSibling = child->nextSibling(); - moveChildTo(toBlock, child, beforeChild, fullRemoveInsert); - child = nextSibling; - } -} - void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) { // makeChildrenNonInline takes a block whose children are *all* inline and it @@ -1214,8 +1140,8 @@ void RenderBlock::collapseAnonymousBoxChild(RenderBlock* parent, RenderObject* c // Delete the now-empty block's lines and nuke it. if (!parent->documentBeingDestroyed()) anonBlock->deleteLineBoxTree(); - if (childFlowThread && !parent->documentBeingDestroyed()) - childFlowThread->removeFlowChildInfo(anonBlock); + if (!parent->documentBeingDestroyed() && childFlowThread && childFlowThread->isRenderNamedFlowThread()) + toRenderNamedFlowThread(childFlowThread)->removeFlowChildInfo(anonBlock); anonBlock->destroy(); } @@ -1241,7 +1167,7 @@ void RenderBlock::removeChild(RenderObject* oldChild) // to clear out inherited column properties by just making a new style, and to also clear the // column span flag if it is set. ASSERT(!inlineChildrenBlock->continuation()); - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK); children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlock->hasLayer()); inlineChildrenBlock->setStyle(newStyle); @@ -1371,18 +1297,12 @@ void RenderBlock::finishDelayUpdateScrollInfo() void RenderBlock::updateScrollInfoAfterLayout() { - if (!hasOverflowClip()) - return; - - if (!hasLayer()) { - updateCachedSizeForOverflowClip(); - return; + if (hasOverflowClip()) { + if (gDelayUpdateScrollInfo) + gDelayedUpdateScrollInfoSet->add(this); + else + layer()->updateScrollInfoAfterLayout(); } - - if (gDelayUpdateScrollInfo) - gDelayedUpdateScrollInfoSet->add(this); - else - layer()->updateScrollInfoAfterLayout(); } void RenderBlock::layout() @@ -1409,7 +1329,7 @@ void RenderBlock::computeInitialRegionRangeForBlock() // effectively clamped to our region range. LayoutUnit oldHeight = logicalHeight(); LayoutUnit oldLogicalTop = logicalTop(); - setLogicalHeight(numeric_limits<LayoutUnit>::max() / 2); + setLogicalHeight(MAX_LAYOUT_UNIT / 2); computeLogicalHeight(); enclosingRenderFlowThread()->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage()); setLogicalHeight(oldHeight); @@ -1423,7 +1343,18 @@ void RenderBlock::computeRegionRangeForBlock() enclosingRenderFlowThread()->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage()); } -void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight, BlockLayoutPass layoutPass) +bool RenderBlock::recomputeLogicalWidth() +{ + LayoutUnit oldWidth = logicalWidth(); + LayoutUnit oldColumnWidth = desiredColumnWidth(); + + computeLogicalWidth(); + calcColumnWidth(); + + return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth(); +} + +void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight) { ASSERT(needsLayout()); @@ -1435,23 +1366,12 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh LayoutRepainter repainter(*this, everHadLayout() && checkForRepaintDuringLayout()); - LayoutUnit oldWidth = logicalWidth(); - LayoutUnit oldColumnWidth = desiredColumnWidth(); - - computeLogicalWidth(); - calcColumnWidth(); + if (recomputeLogicalWidth()) + relayoutChildren = true; m_overflow.clear(); - if (oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth()) - relayoutChildren = true; - - // If nothing changed about our floating positioned objects, let's go ahead and try to place them as - // floats to avoid doing two passes. - BlockLayoutPass floatsLayoutPass = layoutPass; - if (floatsLayoutPass == NormalLayoutPass && !relayoutChildren && !positionedFloatsNeedRelayout()) - floatsLayoutPass = PositionedFloatLayoutPass; - clearFloats(floatsLayoutPass); + clearFloats(); LayoutUnit previousHeight = logicalHeight(); setLogicalHeight(0); @@ -1556,7 +1476,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isBlockFlow() && !child->isFloatingOrPositioned()) { RenderBlock* block = toRenderBlock(child); - if (block->lowestFloatLogicalBottomIncludingPositionedFloats() + block->logicalTop() > newHeight) + if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight) addOverhangingFloats(block, false); } } @@ -1566,7 +1486,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh if (previousHeight != newHeight) relayoutChildren = true; - bool needAnotherLayoutPass = layoutPositionedObjects(relayoutChildren || isRoot()); + layoutPositionedObjects(relayoutChildren || isRoot()); computeRegionRangeForBlock(); @@ -1611,7 +1531,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline)); - if (hasOverflowClipWithLayer()) { + if (hasOverflowClip()) { // Adjust repaint rect for scroll offset repaintRect.move(-scrolledContentOffset()); @@ -1627,11 +1547,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh } } - if (needAnotherLayoutPass && layoutPass == NormalLayoutPass) { - setChildNeedsLayout(true, false); - layoutBlock(false, pageLogicalHeight, PositionedFloatLayoutPass); - } else - setNeedsLayout(false); + setNeedsLayout(false); } void RenderBlock::addOverflowFromChildren() @@ -1703,7 +1619,7 @@ void RenderBlock::addOverflowFromFloats() FloatingObjectSetIterator end = floatingObjectSet.end(); for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { FloatingObject* r = *it; - if (r->m_isDescendant && !r->m_renderer->isPositioned()) + if (r->isDescendant()) addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r))); } return; @@ -1734,7 +1650,7 @@ void RenderBlock::addVisualOverflowFromTheme() if (!style()->hasAppearance()) return; - IntRect inflatedRect = borderBoxRect(); + IntRect inflatedRect = pixelSnappedBorderBoxRect(); theme()->adjustRepaintRect(this, inflatedRect); addVisualOverflow(inflatedRect); } @@ -1772,7 +1688,7 @@ void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marg if (childLayer->staticBlockPosition() != logicalTop) { childLayer->setStaticBlockPosition(logicalTop); if (hasStaticBlockPosition) - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); } } @@ -1791,7 +1707,7 @@ void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo) // for by simply calling canCollapseWithMarginBefore. See // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for // an example of this scenario. - LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? zeroLayoutUnit : marginInfo.margin(); + LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? ZERO_LAYOUT_UNIT : marginInfo.margin(); setLogicalHeight(logicalHeight() + marginOffset); positionNewFloats(); setLogicalHeight(logicalHeight() - marginOffset); @@ -1833,14 +1749,22 @@ bool RenderBlock::handleRunInChild(RenderBox* child) // block. if (!child->isRunIn() || !child->childrenInline()) return false; + // FIXME: We don't handle non-block elements with run-in for now. if (!child->isRenderBlock()) - return false; + return false; + // Run-in child shouldn't intrude into the sibling block if it is part of a // continuation chain. In that case, treat it as a normal block. if (child->isElementContinuation() || child->virtualContinuation()) return false; + // Check if this node is allowed to run-in. E.g. <select> expects its renderer to + // be a RenderListBox or RenderMenuList, and hence cannot be a RenderInline run-in. + Node* runInNode = child->node(); + if (runInNode && runInNode->hasTagName(selectTag)) + return false; + RenderBlock* blockRunIn = toRenderBlock(child); RenderObject* curr = blockRunIn->nextSibling(); if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous() || curr->isFloatingOrPositioned()) @@ -1862,14 +1786,13 @@ bool RenderBlock::handleRunInChild(RenderBox* child) children()->removeChildNode(this, blockRunIn); // Create an inline. - Node* runInNode = blockRunIn->node(); RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document()); inlineRunIn->setStyle(blockRunIn->style()); // Move the nodes from the old child to the new child for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild;) { RenderObject* nextSibling = runInChild->nextSibling(); - blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false); + blockRunIn->children()->removeChildNode(blockRunIn, runInChild); inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content. runInChild = nextSibling; } @@ -2080,7 +2003,7 @@ LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const Margi } LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, - LayoutUnit childLogicalWidth, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) + RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) { LayoutUnit startPosition = startOffsetForContent(region, offsetFromLogicalTopOfFirstPage); @@ -2097,24 +2020,9 @@ LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const Re if (childMarginStart < 0) startOff += childMarginStart; newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit. - } else if (startOff != startPosition) { - // The object is shifting to the "end" side of the block. The object might be centered, so we need to - // recalculate our inline direction margins. Note that the containing block content - // width computation will take into account the delta between |startOff| and |startPosition| - // so that we can just pass the content width in directly to the |computeMarginsInContainingBlockInlineDirection| - // function. - LayoutUnit oldMarginStart = marginStartForChild(child); - LayoutUnit oldMarginEnd = marginEndForChild(child); - RenderBox* mutableChild = const_cast<RenderBox*>(child); - mutableChild->computeInlineDirectionMargins(this, - availableLogicalWidthForLine(blockOffset, false, region, offsetFromLogicalTopOfFirstPage), childLogicalWidth); - newPosition = startOff + marginStartForChild(child); - if (inRenderFlowThread()) { - setMarginStartForChild(mutableChild, oldMarginStart); - setMarginEndForChild(mutableChild, oldMarginEnd); - } - } - + } else if (startOff != startPosition) + newPosition = startOff + childMarginStart; + return newPosition - oldPosition; } @@ -2132,7 +2040,7 @@ void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child) // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need // to shift over as necessary to dodge any floats that might get in the way. if (child->avoidsFloats() && containsFloats() && !inRenderFlowThread()) - newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child), logicalWidthForChild(child)); + newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child)); setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta); } @@ -2211,7 +2119,7 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloa while (box != this) { if (box->normalChildNeedsLayout()) break; - box->setChildNeedsLayout(true, false); + box->setChildNeedsLayout(true, MarkOnlyThis); box = box->containingBlock(); ASSERT(box); if (!box) @@ -2253,13 +2161,12 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloa // Make sure we layout children if they need it. // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into // an auto value. Add a method to determine this, so that we can avoid the relayout. - RenderStyle* childStyle = child->style(); - if (relayoutChildren || ((childStyle->logicalHeight().isPercent() || childStyle->logicalMinHeight().isPercent() || childStyle->logicalMaxHeight().isPercent()) && !isRenderView())) - child->setChildNeedsLayout(true, false); + if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView())) + child->setChildNeedsLayout(true, MarkOnlyThis); // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths. if (relayoutChildren && child->needsPreferredWidthsRecalculation()) - child->setPreferredLogicalWidthsDirty(true, false); + child->setPreferredLogicalWidthsDirty(true, MarkOnlyThis); // Handle the four types of special elements first. These include positioned content, floating content, compacts and // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks. @@ -2313,7 +2220,7 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) { // If an element might be affected by the presence of floats, then always mark it for // layout. - LayoutUnit fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottomIncludingPositionedFloats()); + LayoutUnit fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom()); if (fb > logicalTopEstimate) markDescendantsWithFloats = true; } @@ -2322,7 +2229,7 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay if (markDescendantsWithFloats) childRenderBlock->markAllDescendantsWithFloatsForLayout(); if (!child->isWritingModeRoot()) - previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottomIncludingPositionedFloats()); + previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom()); } if (!child->needsLayout()) @@ -2357,7 +2264,7 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay // When the child shifts to clear an item, its width can // change (because it has more available line width). // So go ahead and mark the item as dirty. - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); } if (childRenderBlock) { @@ -2461,8 +2368,8 @@ bool RenderBlock::simplifiedLayout() simplifiedNormalFlowLayout(); // Lay out our positioned objects if our positioned child bit is set. - if (posChildNeedsLayout() && layoutPositionedObjects(false)) - return false; // If a positioned float is causing our normal flow to change, then we have to bail and do a full layout. + if (posChildNeedsLayout()) + layoutPositionedObjects(false); // Recompute our overflow information. // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only @@ -2482,41 +2389,14 @@ bool RenderBlock::simplifiedLayout() return true; } -bool RenderBlock::positionedFloatsNeedRelayout() -{ - if (!hasPositionedFloats()) - return false; - - RenderBox* positionedObject; - Iterator end = m_positionedObjects->end(); - for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { - positionedObject = *it; - if (!positionedObject->isFloating()) - continue; - - if (positionedObject->needsLayout()) - return true; - - if (positionedObject->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && positionedObject->parent() != this && positionedObject->parent()->isBlockFlow()) - return true; - - if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset())) - return true; - } - - return false; -} - -bool RenderBlock::layoutPositionedObjects(bool relayoutChildren) +void RenderBlock::layoutPositionedObjects(bool relayoutChildren) { if (!m_positionedObjects) - return false; + return; if (hasColumns()) view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns. - bool didFloatingBoxRelayout = false; - RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { @@ -2526,20 +2406,15 @@ bool RenderBlock::layoutPositionedObjects(bool relayoutChildren) // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is // positioned explicitly) this should not incur a performance penalty. if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this)) - r->setChildNeedsLayout(true, false); + r->setChildNeedsLayout(true, MarkOnlyThis); // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths. if (relayoutChildren && r->needsPreferredWidthsRecalculation()) - r->setPreferredLogicalWidthsDirty(true, false); + r->setPreferredLogicalWidthsDirty(true, MarkOnlyThis); if (!r->needsLayout()) r->markForPaginationRelayoutIfNeeded(); - // FIXME: Technically we could check the old placement and the new placement of the box and only invalidate if - // the margin box of the object actually changed. - if (r->needsLayout() && r->isFloating()) - didFloatingBoxRelayout = true; - // 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()) @@ -2556,20 +2431,26 @@ bool RenderBlock::layoutPositionedObjects(bool relayoutChildren) r->computeLogicalWidth(); oldLogicalTop = logicalTopForChild(r); } - - r->layoutIfNeeded(); + r->layoutIfNeeded(); + + // Adjust the static position of a center-aligned inline positioned object with a block child now that the child's width has been computed. + if (!r->parent()->isRenderView() && r->parent()->isRenderBlock() && r->firstChild() && r->style()->position() == AbsolutePosition + && r->style()->isOriginalDisplayInlineType() && (r->style()->textAlign() == CENTER || r->style()->textAlign() == WEBKIT_CENTER)) { + RenderBlock* block = toRenderBlock(r->parent()); + LayoutUnit blockHeight = block->logicalHeight(); + block->setStaticInlinePositionForChild(r, blockHeight, block->startAlignedOffsetForLine(r, blockHeight, false)); + } + // Lay out again if our estimate was wrong. if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop) { - r->setChildNeedsLayout(true, false); + r->setChildNeedsLayout(true, MarkOnlyThis); 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. - - return didFloatingBoxRelayout; } void RenderBlock::markPositionedObjectsForLayout() @@ -2591,7 +2472,7 @@ void RenderBlock::markForPaginationRelayoutIfNeeded() return; if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset())) - setChildNeedsLayout(true, false); + setChildNeedsLayout(true, MarkOnlyThis); } void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) @@ -2611,7 +2492,7 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) // Only repaint the object if it is overhanging, is not in its own layer, and // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter // condition is replaced with being a descendant of us. - if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) { + if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->shouldPaint()) && !r->m_renderer->hasSelfPaintingLayer()) { r->m_renderer->repaint(); r->m_renderer->repaintOverhangingFloats(); } @@ -2644,7 +2525,7 @@ void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with // z-index. We paint after we painted the background/border, so that the scrollbars will // sit above the background/border. - if (hasOverflowClipWithLayer() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this)) + if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this)) layer()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect); } @@ -2668,9 +2549,9 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& pain bool antialias = shouldAntialiasLines(paintInfo.context); if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { - LayoutUnit currLogicalLeftOffset = style()->isLeftToRightDirection() ? zeroLayoutUnit : contentLogicalWidth(); + LayoutUnit currLogicalLeftOffset = style()->isLeftToRightDirection() ? ZERO_LAYOUT_UNIT : contentLogicalWidth(); LayoutUnit ruleAdd = logicalLeftOffsetForContent(); - LayoutUnit ruleLogicalLeft = style()->isLeftToRightDirection() ? zeroLayoutUnit : contentLogicalWidth(); + LayoutUnit ruleLogicalLeft = style()->isLeftToRightDirection() ? ZERO_LAYOUT_UNIT : contentLogicalWidth(); LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth(); BoxSide boxSide = isHorizontalWritingMode() ? style()->isLeftToRightDirection() ? BSLeft : BSRight @@ -2780,13 +2661,10 @@ void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOf if (document()->didLayoutWithPendingStylesheets() && !isRenderView()) return; - // We don't want to hand off painting in the line box tree with the accumulated error of the render tree, as this will cause - // us to mess up painting aligned things (such as underlines in text) with both the render tree and line box tree's error. - LayoutPoint roundedPaintOffset = roundedIntPoint(paintOffset); if (childrenInline()) - m_lineBoxes.paint(this, paintInfo, roundedPaintOffset); + m_lineBoxes.paint(this, paintInfo, paintOffset); else - paintChildren(paintInfo, roundedPaintOffset); + paintChildren(paintInfo, paintOffset); } void RenderBlock::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset) @@ -2918,7 +2796,10 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs // 6. paint continuation outlines. if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { RenderInline* inlineCont = inlineElementContinuation(); - if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) { + // FIXME: For now, do not add continuations for outline painting by our containing block if we are a relative positioned + // anonymous block (i.e. have our own layer). This is because a block depends on renderers in its continuation table being + // in the same layer. + if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE && !hasLayer()) { RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer()); RenderBlock* cb = containingBlock(); @@ -2970,7 +2851,7 @@ void RenderBlock::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffs for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { FloatingObject* r = *it; // Only paint the object if our m_shouldPaint flag is set. - if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { + if (r->shouldPaint() && !r->m_renderer->hasSelfPaintingLayer()) { PaintInfo currentPaintInfo(paintInfo); currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->m_renderer->x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->m_renderer->y())); @@ -3282,8 +3163,8 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPo // Now paint the gaps for the lines. for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) { - LayoutUnit selTop = curr->selectionTop(); - LayoutUnit selHeight = curr->selectionHeight(); + LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock(); + LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock(); if (!containsStart && !lastSelectedLine && selectionState() != SelectionStart && selectionState() != SelectionBoth) @@ -3475,6 +3356,38 @@ LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, Layo return logicalRight; } +RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) const +{ + if (isSelectionRoot()) + return 0; + + const RenderBox* object = this; + RenderObject* sibling; + do { + sibling = object->previousSibling(); + while (sibling && (!sibling->isRenderBlock() || toRenderBlock(sibling)->isSelectionRoot())) + sibling = sibling->previousSibling(); + + offset -= LayoutSize(object->logicalLeft(), object->logicalTop()); + object = object->parentBox(); + } while (!sibling && object && object->isRenderBlock() && !toRenderBlock(object)->isSelectionRoot()); + + if (!sibling) + return 0; + + RenderBlock* beforeBlock = toRenderBlock(sibling); + + offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop()); + + RenderObject* child = beforeBlock->lastChild(); + while (child && child->isRenderBlock()) { + beforeBlock = toRenderBlock(child); + offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop()); + child = beforeBlock->lastChild(); + } + return beforeBlock; +} + void RenderBlock::insertPositionedObject(RenderBox* o) { ASSERT(!isAnonymousBlock()); @@ -3487,12 +3400,18 @@ void RenderBlock::insertPositionedObject(RenderBox* o) m_positionedObjects = adoptPtr(new PositionedObjectsListHashSet); m_positionedObjects->add(o); + + if (o->style()->position() == FixedPosition && view()) + view()->insertFixedPositionedObject(o); } void RenderBlock::removePositionedObject(RenderBox* o) { if (m_positionedObjects) m_positionedObjects->remove(o); + + if (view()) + view()->removeFixedPositionedObject(o); } void RenderBlock::removePositionedObjects(RenderBlock* o) @@ -3510,7 +3429,7 @@ void RenderBlock::removePositionedObjects(RenderBlock* o) r = *it; if (!o || r->isDescendantOf(o)) { if (o) - r->setChildNeedsLayout(true, false); + r->setChildNeedsLayout(true, MarkOnlyThis); // It is parent blocks job to add positioned child to positioned objects list of its containing block // Parent layout needs to be invalidated to ensure this happens. @@ -3549,23 +3468,21 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o) // Our location is irrelevant if we're unsplittable or no pagination is in effect. // Just go ahead and lay out the float. - if (!o->isPositioned()) { - bool isChildRenderBlock = o->isRenderBlock(); - if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageLogicalHeightChanged()) - o->setChildNeedsLayout(true, false); + bool isChildRenderBlock = o->isRenderBlock(); + if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageLogicalHeightChanged()) + o->setChildNeedsLayout(true, MarkOnlyThis); - bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout(); - if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) // We are unsplittable if we're a block flow root. - o->layoutIfNeeded(); - else { - o->computeLogicalWidth(); - o->computeBlockDirectionMargins(this); - } + bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout(); + if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) // We are unsplittable if we're a block flow root. + o->layoutIfNeeded(); + else { + o->computeLogicalWidth(); + o->computeBlockDirectionMargins(this); } setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o)); - newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will. - newObj->m_isDescendant = true; + newObj->setShouldPaint(!o->hasSelfPaintingLayer()); // If a layer exists, the float will paint itself. Otherwise someone else will. + newObj->setIsDescendant(true); newObj->m_renderer = o; m_floatingObjects->add(newObj); @@ -3585,8 +3502,8 @@ void RenderBlock::removeFloatingObject(RenderBox* o) LayoutUnit logicalBottom = logicalBottomForFloat(r); // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995. - if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == numeric_limits<LayoutUnit>::max()) - logicalBottom = numeric_limits<LayoutUnit>::max(); + if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == MAX_LAYOUT_UNIT) + logicalBottom = MAX_LAYOUT_UNIT; else { // Special-case zero- and less-than-zero-height floats: those don't touch // the line that they're on, but it still needs to be dirtied. This is @@ -3714,9 +3631,8 @@ bool RenderBlock::positionNewFloats() for (; it != end; ++it) { FloatingObject* floatingObject = *it; // The containing block is responsible for positioning floats, so if we have floats in our - // list that come from somewhere else, do not attempt to position them. Also don't attempt to handle - // positioned floats, since the positioning layout code handles those. - if (floatingObject->renderer()->containingBlock() != this || floatingObject->renderer()->isPositioned()) + // list that come from somewhere else, do not attempt to position them. + if (floatingObject->renderer()->containingBlock() != this) continue; RenderBox* childBox = floatingObject->renderer(); @@ -3765,7 +3681,7 @@ bool RenderBlock::positionNewFloats() setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox)); if (childBlock) - childBlock->setChildNeedsLayout(true, false); + childBlock->setChildNeedsLayout(true, MarkOnlyThis); childBox->layoutIfNeeded(); } } @@ -3786,7 +3702,7 @@ void RenderBlock::newLine(EClear clear) { positionNewFloats(); // set y position - int newY = 0; + LayoutUnit newY = 0; switch (clear) { case CLEFT: @@ -3816,7 +3732,7 @@ void RenderBlock::addPercentHeightDescendant(RenderBox* descendant) descendantSet = new HashSet<RenderBox*>; gPercentHeightDescendantsMap->set(this, descendantSet); } - bool added = descendantSet->add(descendant).second; + bool added = descendantSet->add(descendant).isNewEntry; if (!added) { ASSERT(gPercentHeightContainerMap->get(descendant)); ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this)); @@ -3902,9 +3818,12 @@ inline void RenderBlock::FloatIntervalSearchAdapter<FloatTypeValue>::collectIfNe LayoutUnit RenderBlock::textIndentOffset() const { LayoutUnit cw = 0; + RenderView* renderView = 0; if (style()->textIndent().isPercent()) cw = containingBlock()->availableLogicalWidth(); - return style()->textIndent().calcMinValue(cw); + else if (style()->textIndent().isViewportPercentage()) + renderView = view(); + return minimumValueForLength(style()->textIndent(), cw, renderView); } LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const @@ -4027,7 +3946,7 @@ LayoutUnit RenderBlock::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) co if (!m_floatingObjects) return logicalHeight; - LayoutUnit bottom = numeric_limits<LayoutUnit>::max(); + LayoutUnit bottom = MAX_LAYOUT_UNIT; const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { @@ -4037,7 +3956,7 @@ LayoutUnit RenderBlock::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) co bottom = min(floatBottom, bottom); } - return bottom == numeric_limits<LayoutUnit>::max() ? zeroLayoutUnit : bottom; + return bottom == MAX_LAYOUT_UNIT ? ZERO_LAYOUT_UNIT : bottom; } LayoutUnit RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const @@ -4062,7 +3981,7 @@ void RenderBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit l RootInlineBox* lowestDirtyLine = lastRootBox(); RootInlineBox* afterLowest = lowestDirtyLine; - while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < numeric_limits<LayoutUnit>::max()) { + while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < MAX_LAYOUT_UNIT) { afterLowest = lowestDirtyLine; lowestDirtyLine = lowestDirtyLine->prevRootBox(); } @@ -4073,40 +3992,21 @@ void RenderBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit l } } -void RenderBlock::addPositionedFloats() -{ - if (!m_positionedObjects) - return; - - Iterator end = m_positionedObjects->end(); - for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { - RenderBox* positionedObject = *it; - if (!positionedObject->isFloating()) - continue; - - ASSERT(!positionedObject->needsLayout()); - - // If we're a positioned float, then we need to insert ourselves as a floating object also. We only do - // this after the positioned object has received a layout, since otherwise the dimensions and placement - // won't be correct. - FloatingObject* floatingObject = insertFloatingObject(positionedObject); - setLogicalLeftForFloat(floatingObject, logicalLeftForChild(positionedObject) - marginLogicalLeftForChild(positionedObject)); - setLogicalTopForFloat(floatingObject, logicalTopForChild(positionedObject) - marginBeforeForChild(positionedObject)); - setLogicalHeightForFloat(floatingObject, logicalHeightForChild(positionedObject) + marginBeforeForChild(positionedObject) + marginAfterForChild(positionedObject)); - - m_floatingObjects->addPlacedObject(floatingObject); - - m_hasPositionedFloats = true; - } -} - -void RenderBlock::clearFloats(BlockLayoutPass layoutPass) +void RenderBlock::clearFloats() { if (m_floatingObjects) m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode()); - // Clear our positioned floats boolean. - m_hasPositionedFloats = false; + HashSet<RenderBox*> oldIntrudingFloatSet; + if (!childrenInline() && m_floatingObjects) { + const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { + FloatingObject* floatingObject = *it; + if (!floatingObject->isDescendant()) + oldIntrudingFloatSet.add(floatingObject->m_renderer); + } + } // Inline blocks are covered by the isReplaced() check in the avoidFloats method. if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrPositioned() || isTableCell()) { @@ -4114,8 +4014,8 @@ void RenderBlock::clearFloats(BlockLayoutPass layoutPass) deleteAllValues(m_floatingObjects->set()); m_floatingObjects->clear(); } - if (layoutPass == PositionedFloatLayoutPass) - addPositionedFloats(); + if (!oldIntrudingFloatSet.isEmpty()) + markAllDescendantsWithFloatsForLayout(); return; } @@ -4135,9 +4035,6 @@ void RenderBlock::clearFloats(BlockLayoutPass layoutPass) m_floatingObjects->clear(); } - if (layoutPass == PositionedFloatLayoutPass) - addPositionedFloats(); - // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add // floats in an invalid context. This will cause a crash arising from a bad cast on the parent. // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG. @@ -4148,7 +4045,7 @@ void RenderBlock::clearFloats(BlockLayoutPass layoutPass) // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted // to avoid floats. RenderBlock* parentBlock = toRenderBlock(parent()); - bool parentHasFloats = parentBlock->hasPositionedFloats(); + bool parentHasFloats = false; RenderObject* prev = previousSibling(); while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) { if (prev->isFloating()) @@ -4164,19 +4061,19 @@ void RenderBlock::clearFloats(BlockLayoutPass layoutPass) LayoutUnit logicalLeftOffset = 0; if (prev) logicalTopOffset -= toRenderBox(prev)->logicalTop(); - else if (!parentHasFloats) { + else { prev = parentBlock; logicalLeftOffset += parentBlock->logicalLeftOffsetForContent(); } // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space. RenderBlock* block = toRenderBlock(prev); - if (block && block->m_floatingObjects && block->lowestFloatLogicalBottomIncludingPositionedFloats() > logicalTopOffset) + if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset) addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset); if (childrenInline()) { - LayoutUnit changeLogicalTop = numeric_limits<LayoutUnit>::max(); - LayoutUnit changeLogicalBottom = numeric_limits<LayoutUnit>::min(); + LayoutUnit changeLogicalTop = MAX_LAYOUT_UNIT; + LayoutUnit changeLogicalBottom = MIN_LAYOUT_UNIT; if (m_floatingObjects) { const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); @@ -4218,7 +4115,7 @@ void RenderBlock::clearFloats(BlockLayoutPass layoutPass) RendererToFloatInfoMap::iterator end = floatMap.end(); for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) { FloatingObject* floatingObject = (*it).second; - if (!floatingObject->m_isDescendant) { + if (!floatingObject->isDescendant()) { changeLogicalTop = 0; changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject)); } @@ -4226,6 +4123,19 @@ void RenderBlock::clearFloats(BlockLayoutPass layoutPass) deleteAllValues(floatMap); markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom); + } else if (!oldIntrudingFloatSet.isEmpty()) { + // If there are previously intruding floats that no longer intrude, then children with floats + // should also get layout because they might need their floating object lists cleared. + if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size()) + markAllDescendantsWithFloatsForLayout(); + else { + const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); + FloatingObjectSetIterator end = floatingObjectSet.end(); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it) + oldIntrudingFloatSet.remove((*it)->m_renderer); + if (!oldIntrudingFloatSet.isEmpty()) + markAllDescendantsWithFloatsForLayout(); + } } } @@ -4244,7 +4154,7 @@ LayoutUnit RenderBlock::addOverhangingFloats(RenderBlock* child, bool makeChildP FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end(); for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) { FloatingObject* r = *childIt; - LayoutUnit logicalBottomForFloat = min(this->logicalBottomForFloat(r), numeric_limits<LayoutUnit>::max() - childLogicalTop); + LayoutUnit logicalBottomForFloat = min(this->logicalBottomForFloat(r), MAX_LAYOUT_UNIT - childLogicalTop); LayoutUnit logicalBottom = childLogicalTop + logicalBottomForFloat; lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom); @@ -4261,11 +4171,11 @@ LayoutUnit RenderBlock::addOverhangingFloats(RenderBlock* child, bool makeChildP // far out as we can, to the outermost block that overlaps the float, stopping only // if we hit a self-painting layer boundary. if (r->m_renderer->enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) - r->m_shouldPaint = false; + r->setShouldPaint(false); else - floatingObj->m_shouldPaint = false; - - floatingObj->m_isDescendant = true; + floatingObj->setShouldPaint(false); + + floatingObj->setIsDescendant(true); // We create the floating object list lazily. if (!m_floatingObjects) @@ -4274,19 +4184,19 @@ LayoutUnit RenderBlock::addOverhangingFloats(RenderBlock* child, bool makeChildP m_floatingObjects->add(floatingObj); } } else { - if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer() && - r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingFloatPaintingLayer() == child->enclosingFloatPaintingLayer()) { + if (makeChildPaintOtherFloats && !r->shouldPaint() && !r->m_renderer->hasSelfPaintingLayer() + && r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingFloatPaintingLayer() == child->enclosingFloatPaintingLayer()) { // The float is not overhanging from this block, so if it is a descendant of the child, the child should // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing // layer. // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats // it should paint. - r->m_shouldPaint = true; + r->setShouldPaint(true); } // Since the float doesn't overhang, it didn't get put into our list. We need to go ahead and add its overflow in to the // child now. - if (r->m_isDescendant) + if (r->isDescendant()) child->addOverflowFromChild(r->m_renderer, LayoutSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r))); } } @@ -4337,7 +4247,7 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, LayoutUnit logicalLeftOf floatingObj->setY(floatingObj->y() + prev->marginTop()); } - floatingObj->m_shouldPaint = false; // We are not in the direct inheritance chain for this float. We will never paint it. + floatingObj->setShouldPaint(false); // We are not in the direct inheritance chain for this float. We will never paint it. floatingObj->m_renderer = r->m_renderer; // We create the floating object list lazily. @@ -4365,7 +4275,8 @@ void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove if (!everHadLayout()) return; - setChildNeedsLayout(true, !inLayout); + MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain; + setChildNeedsLayout(true, markParents); if (floatToRemove) removeFloatingObject(floatToRemove); @@ -4386,26 +4297,21 @@ void RenderBlock::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove) { if (!m_floatingObjects) return; + const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); - for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { - if (logicalBottomForFloat(*it) > logicalHeight()) { + + for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) { + if (!next->isRenderBlock() || next->isFloatingOrPositioned() || toRenderBlock(next)->avoidsFloats()) + continue; + + RenderBlock* nextBlock = toRenderBlock(next); + for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { RenderBox* floatingBox = (*it)->renderer(); if (floatToRemove && floatingBox != floatToRemove) continue; - - RenderObject* next = nextSibling(); - while (next) { - if (next->isRenderBlock() && !next->isFloatingOrPositioned() && !toRenderBlock(next)->avoidsFloats()) { - RenderBlock* nextBlock = toRenderBlock(next); - if (nextBlock->containsFloat(floatingBox)) - nextBlock->markAllDescendantsWithFloatsForLayout(floatingBox); - else - break; - } - - next = next->nextSibling(); - } + if (nextBlock->containsFloat(floatingBox)) + nextBlock->markAllDescendantsWithFloatsForLayout(floatingBox); } } } @@ -4434,7 +4340,7 @@ LayoutUnit RenderBlock::getClearDelta(RenderBox* child, LayoutUnit logicalTop) } // We also clear floats if we are too big to sit on the same line as a float (and wish to avoid floats by default). - LayoutUnit result = clearSet ? max<LayoutUnit>(0, logicalBottom - logicalTop) : zeroLayoutUnit; + LayoutUnit result = clearSet ? max<LayoutUnit>(0, logicalBottom - logicalTop) : ZERO_LAYOUT_UNIT; if (!result && child->avoidsFloats()) { LayoutUnit newLogicalTop = logicalTop; while (true) { @@ -4474,10 +4380,10 @@ LayoutUnit RenderBlock::getClearDelta(RenderBox* child, LayoutUnit logicalTop) bool RenderBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset) { - if (!scrollsOverflow() || !hasLayer()) + if (!scrollsOverflow()) return false; - return layer()->hitTestOverflowControls(result, pointInContainer - toLayoutSize(accumulatedOffset)); + return layer()->hitTestOverflowControls(result, roundedIntPoint(pointInContainer - toLayoutSize(accumulatedOffset))); } bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) @@ -4554,7 +4460,7 @@ bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& re for (FloatingObjectSetIterator it = floatingObjectSet.end(); it != begin;) { --it; FloatingObject* floatingObject = *it; - if (floatingObject->m_shouldPaint && !floatingObject->m_renderer->hasSelfPaintingLayer()) { + if (floatingObject->shouldPaint() && !floatingObject->m_renderer->hasSelfPaintingLayer()) { LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->x(); LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->y(); LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset)); @@ -4884,7 +4790,10 @@ int RenderBlock::columnGap() const } void RenderBlock::calcColumnWidth() -{ +{ + if (document()->regionBasedColumnsEnabled()) + return; + // Calculate our column width and column count. // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744 unsigned desiredColumnCount = 1; @@ -5018,7 +4927,7 @@ bool RenderBlock::layoutColumns(bool hasSpecifiedPageLogicalHeight, LayoutUnit p view()->layoutState()->pageLogicalOffset(borderBefore() + paddingBefore() + contentLogicalHeight()) - colInfo->forcedBreakOffset()); columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks); } - } else if (contentLogicalHeight() > pageLogicalHeight * desiredColumnCount) { + } else if (contentLogicalHeight() > boundedMultiply(pageLogicalHeight, desiredColumnCount)) { // Now that we know the intrinsic height of the columns, we have to rebalance them. columnHeight = max<LayoutUnit>(colInfo->minimumColumnHeight(), ceilf((float)contentLogicalHeight() / desiredColumnCount)); } @@ -5211,11 +5120,11 @@ void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point) ColumnInfo* colInfo = columnInfo(); LayoutUnit logicalLeft = logicalLeftOffsetForContent(); - size_t colCount = columnCount(colInfo); + unsigned colCount = columnCount(colInfo); LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth(); LayoutUnit colLogicalHeight = colInfo->columnHeight(); - for (size_t i = 0; i < colCount; ++i) { + for (unsigned i = 0; i < colCount; ++i) { // Compute the edges for a given column in the block progression direction. LayoutRect sliceRect = LayoutRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight); if (!isHorizontalWritingMode()) @@ -5409,7 +5318,7 @@ static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result) { - LayoutUnit snappedResult = ceiledLayoutUnit(result); + LayoutUnit snappedResult = ceilf(result); preferredWidth = max(snappedResult, preferredWidth); } @@ -5420,7 +5329,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths() RenderStyle* styleToUse = style(); RenderBlock* containingBlock = this->containingBlock(); - LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : zeroLayoutUnit; + LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : ZERO_LAYOUT_UNIT; // If we are at the start of a line, we want to ignore all white-space. // Also strip spaces if we previously had text that ended in a trailing space. @@ -5541,7 +5450,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths() LayoutUnit ti = 0; if (!addedTextIndent) { addedTextIndent = true; - ti = styleToUse->textIndent().calcMinValue(cw); + ti = minimumValueForLength(styleToUse->textIndent(), cw, view()); childMin += ti; childMax += ti; } @@ -5612,7 +5521,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths() LayoutUnit ti = 0; if (!addedTextIndent) { addedTextIndent = true; - ti = styleToUse->textIndent().calcMinValue(cw); + ti = minimumValueForLength(styleToUse->textIndent(), cw, view()); childMin+=ti; beginMin += ti; childMax+=ti; beginMax += ti; } @@ -5806,11 +5715,11 @@ LayoutUnit RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, if (firstLine && document()->usesFirstLineRules()) { RenderStyle* s = style(firstLine); if (s != style()) - return s->computedLineHeight(); + return s->computedLineHeight(view()); } if (m_lineHeight == -1) - m_lineHeight = style()->computedLineHeight(); + m_lineHeight = style()->computedLineHeight(view()); return m_lineHeight; } @@ -5838,9 +5747,9 @@ LayoutUnit RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLi bool ignoreBaseline = (layer() && (layer()->marquee() || (direction == HorizontalLine ? (layer()->verticalScrollbar() || layer()->scrollYOffset() != 0) : (layer()->horizontalScrollbar() || layer()->scrollXOffset() != 0)))) || (isWritingModeRoot() && !isRubyRun()); - int baselinePos = ignoreBaseline ? LayoutUnit(-1) : lastLineBoxBaseline(); + LayoutUnit baselinePos = ignoreBaseline ? static_cast<LayoutUnit>(-1) : lastLineBoxBaseline(); - int bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth(); + LayoutUnit bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth(); if (baselinePos != -1 && baselinePos <= bottomOfContent) return direction == HorizontalLine ? marginTop() + baselinePos : marginRight() + baselinePos; @@ -5993,120 +5902,67 @@ static inline RenderObject* findFirstLetterBlock(RenderBlock* start) return 0; } -void RenderBlock::updateFirstLetter() +void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderObject* currentChild) { - if (!document()->usesFirstLetterRules()) - return; - // Don't recur - if (style()->styleType() == FIRST_LETTER) - return; - - // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find - // an efficient way to check for that situation though before implementing anything. - RenderObject* firstLetterBlock = findFirstLetterBlock(this); - if (!firstLetterBlock) - return; + RenderObject* firstLetter = currentChild->parent(); + RenderObject* firstLetterContainer = firstLetter->parent(); + RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer); + ASSERT(firstLetter->isFloating() || firstLetter->isInline()); - // Drill into inlines looking for our first text child. - RenderObject* currChild = firstLetterBlock->firstChild(); - while (currChild) { - if (currChild->isText()) - break; - if (currChild->isListMarker()) - currChild = currChild->nextSibling(); - else if (currChild->isFloatingOrPositioned()) { - if (currChild->style()->styleType() == FIRST_LETTER) { - currChild = currChild->firstChild(); - break; - } - currChild = currChild->nextSibling(); - } else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList()) - break; - else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && canHaveGeneratedChildren(currChild)) { - // We found a lower-level node with first-letter, which supersedes the higher-level style - firstLetterBlock = currChild; - currChild = currChild->firstChild(); - } + if (Node::diff(firstLetter->style(), pseudoStyle, document()) == 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 - currChild = currChild->firstChild(); - } - - if (!currChild) - return; - - // If the child already has style, then it has already been created, so we just want - // to update it. - if (currChild->parent()->style()->styleType() == FIRST_LETTER) { - RenderObject* firstLetter = currChild->parent(); - RenderObject* firstLetterContainer = firstLetter->parent(); - RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer); - ASSERT(firstLetter->isFloating() || firstLetter->isInline()); - - 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. - LayoutStateDisabler layoutStateDisabler(view()); - while (RenderObject* child = firstLetter->firstChild()) { - if (child->isText()) - toRenderText(child)->removeAndDestroyTextBoxes(); - firstLetter->removeChild(child); - newFirstLetter->addChild(child, 0); - } - - RenderTextFragment* remainingText = 0; - RenderObject* nextSibling = firstLetter->nextSibling(); - RenderObject* remainingTextObject = toRenderBoxModelObject(firstLetter)->firstLetterRemainingText(); - if (remainingTextObject && remainingTextObject->isText() && toRenderText(remainingTextObject)->isTextFragment()) - remainingText = toRenderTextFragment(remainingTextObject); - if (remainingText) { - ASSERT(remainingText->isAnonymous() || remainingText->node()->renderer() == remainingText); - // Replace the old renderer with the new one. - remainingText->setFirstLetter(newFirstLetter); - toRenderBoxModelObject(newFirstLetter)->setFirstLetterRemainingText(remainingText); - } - firstLetter->destroy(); - firstLetter = newFirstLetter; - firstLetterContainer->addChild(firstLetter, nextSibling); - } else - firstLetter->setStyle(pseudoStyle); - - for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) { - if (genChild->isText()) - genChild->setStyle(pseudoStyle); - } + newFirstLetter = new (renderArena()) RenderBlock(document()); + newFirstLetter->setStyle(pseudoStyle); + + // Move the first letter into the new renderer. + LayoutStateDisabler layoutStateDisabler(view()); + while (RenderObject* child = firstLetter->firstChild()) { + if (child->isText()) + toRenderText(child)->removeAndDestroyTextBoxes(); + firstLetter->removeChild(child); + newFirstLetter->addChild(child, 0); + } + + RenderTextFragment* remainingText = 0; + RenderObject* nextSibling = firstLetter->nextSibling(); + RenderObject* remainingTextObject = toRenderBoxModelObject(firstLetter)->firstLetterRemainingText(); + if (remainingTextObject && remainingTextObject->isText() && toRenderText(remainingTextObject)->isTextFragment()) + remainingText = toRenderTextFragment(remainingTextObject); + if (remainingText) { + ASSERT(remainingText->isAnonymous() || remainingText->node()->renderer() == remainingText); + // Replace the old renderer with the new one. + remainingText->setFirstLetter(newFirstLetter); + toRenderBoxModelObject(newFirstLetter)->setFirstLetterRemainingText(remainingText); + } + firstLetter->destroy(); + firstLetter = newFirstLetter; + firstLetterContainer->addChild(firstLetter, nextSibling); + } else + firstLetter->setStyle(pseudoStyle); - return; + for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) { + if (genChild->isText()) + genChild->setStyle(pseudoStyle); } +} - if (!currChild->isText() || currChild->isBR()) - return; - - // If the child does not already have style, we create it here. - RenderObject* firstLetterContainer = currChild->parent(); - - // Our layout state is not valid for the repaints we are going to trigger by - // adding and removing children of firstLetterContainer. - LayoutStateDisabler layoutStateDisabler(view()); - - RenderText* textObj = toRenderText(currChild); - - // Create our pseudo style now that we have our firstLetterContainer determined. +void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, RenderObject* currentChild) +{ + RenderObject* firstLetterContainer = currentChild->parent(); 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); + firstLetterContainer->addChild(firstLetter, currentChild); + + RenderText* textObj = toRenderText(currentChild); // 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 @@ -6159,6 +6015,63 @@ void RenderBlock::updateFirstLetter() } } +void RenderBlock::updateFirstLetter() +{ + if (!document()->usesFirstLetterRules()) + return; + // Don't recur + if (style()->styleType() == FIRST_LETTER) + return; + + // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find + // an efficient way to check for that situation though before implementing anything. + RenderObject* firstLetterBlock = findFirstLetterBlock(this); + if (!firstLetterBlock) + return; + + // Drill into inlines looking for our first text child. + RenderObject* currChild = firstLetterBlock->firstChild(); + while (currChild) { + if (currChild->isText()) + break; + if (currChild->isListMarker()) + currChild = currChild->nextSibling(); + else if (currChild->isFloatingOrPositioned()) { + if (currChild->style()->styleType() == FIRST_LETTER) { + currChild = currChild->firstChild(); + break; + } + currChild = currChild->nextSibling(); + } else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList()) + break; + else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && canHaveGeneratedChildren(currChild)) { + // We found a lower-level node with first-letter, which supersedes the higher-level style + firstLetterBlock = currChild; + currChild = currChild->firstChild(); + } else + currChild = currChild->firstChild(); + } + + if (!currChild) + return; + + // If the child already has style, then it has already been created, so we just want + // to update it. + if (currChild->parent()->style()->styleType() == FIRST_LETTER) { + updateFirstLetterStyle(firstLetterBlock, currChild); + return; + } + + if (!currChild->isText() || currChild->isBR()) + return; + + // Our layout state is not valid for the repaints we are going to trigger by + // adding and removing children of firstLetterContainer. + LayoutStateDisabler layoutStateDisabler(view()); + + createFirstLetterRenderer(firstLetterBlock, currChild); +} + // Helper methods for obtaining the last line, computing line counts and heights for line counts // (crawling into blocks). static bool shouldCheckLines(RenderObject* obj) @@ -6196,7 +6109,7 @@ static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, if (block->childrenInline()) { for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) { if (++count == l) - return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : zeroLayoutUnit); + return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : ZERO_LAYOUT_UNIT); } } else { @@ -6205,7 +6118,7 @@ static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, if (shouldCheckLines(obj)) { int result = getHeightForLineCount(toRenderBlock(obj), l, false, count); if (result != -1) - return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : zeroLayoutUnit); + return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : ZERO_LAYOUT_UNIT); } else if (!obj->isFloatingOrPositioned() && !obj->isRunIn()) normalFlowChildWithoutLines = obj; @@ -6278,7 +6191,7 @@ void RenderBlock::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { FloatingObject* r = *it; // Only examine the object if our m_shouldPaint flag is set. - if (r->m_shouldPaint) { + if (r->shouldPaint()) { LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->m_renderer->x(); LayoutUnit floatRight = floatLeft + r->m_renderer->width(); left = min(left, floatLeft); @@ -6295,11 +6208,11 @@ void RenderBlock::borderFitAdjust(LayoutRect& rect) const return; // Walk any normal flow lines to snugly fit. - LayoutUnit left = numeric_limits<LayoutUnit>::max(); - LayoutUnit right = numeric_limits<LayoutUnit>::min(); + LayoutUnit left = MAX_LAYOUT_UNIT; + LayoutUnit right = MIN_LAYOUT_UNIT; LayoutUnit oldWidth = rect.width(); adjustForBorderFit(0, left, right); - if (left != numeric_limits<LayoutUnit>::max()) { + if (left != MAX_LAYOUT_UNIT) { left = min(left, oldWidth - (borderRight() + paddingRight())); left -= (borderLeft() + paddingLeft()); @@ -6308,7 +6221,7 @@ void RenderBlock::borderFitAdjust(LayoutRect& rect) const rect.expand(-left, 0); } } - if (right != numeric_limits<LayoutUnit>::min()) { + if (right != MIN_LAYOUT_UNIT) { right = max(right, borderLeft() + paddingLeft()); right += (borderRight() + paddingRight()); @@ -6365,7 +6278,7 @@ void RenderBlock::setPaginationStrut(LayoutUnit strut) m_rareData->m_paginationStrut = strut; } -void RenderBlock::setPageLogicalOffset(int logicalOffset) +void RenderBlock::setPageLogicalOffset(LayoutUnit logicalOffset) { if (!m_rareData) { if (!logicalOffset) @@ -6513,14 +6426,23 @@ LayoutRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, La switch (alignment) { case alignLeft: + if (currentStyle->isLeftToRightDirection()) + x += textIndentOffset(); break; case alignCenter: x = (x + w - (borderRight() + paddingRight())) / 2; + if (currentStyle->isLeftToRightDirection()) + x += textIndentOffset() / 2; + else + x -= textIndentOffset() / 2; break; case alignRight: x = w - (borderRight() + paddingRight()) - caretWidth; + if (!currentStyle->isLeftToRightDirection()) + x -= textIndentOffset(); break; } + x = min(x, w - borderRight() - paddingRight() - caretWidth); if (extraWidthToEndOfLine) { if (isRenderBlock()) { @@ -6593,52 +6515,13 @@ void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& a inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location())); } -RenderBlock* RenderBlock::createAnonymousBlock(bool isFlexibleBox) const -{ - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); - - RenderBlock* newBox = 0; - if (isFlexibleBox) { - newStyle->setDisplay(BOX); - newBox = new (renderArena()) RenderDeprecatedFlexibleBox(document() /* anonymous box */); - } else { - newStyle->setDisplay(BLOCK); - newBox = new (renderArena()) RenderBlock(document() /* anonymous box */); - } - - newBox->setStyle(newStyle.release()); - return newBox; -} - -RenderBlock* RenderBlock::createAnonymousBlockWithSameTypeAs(RenderBlock* otherAnonymousBlock) const -{ - if (otherAnonymousBlock->isAnonymousColumnsBlock()) - return createAnonymousColumnsBlock(); - if (otherAnonymousBlock->isAnonymousColumnSpanBlock()) - return createAnonymousColumnSpanBlock(); - return createAnonymousBlock(otherAnonymousBlock->style()->display() == BOX); -} - -RenderBlock* RenderBlock::createAnonymousColumnsBlock() const -{ - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); - newStyle->inheritColumnPropertiesFrom(style()); - newStyle->setDisplay(BLOCK); - - RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */); - newBox->setStyle(newStyle.release()); - return newBox; -} - -RenderBlock* RenderBlock::createAnonymousColumnSpanBlock() const +RenderBox* RenderBlock::createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const { - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); - newStyle->setColumnSpan(ColumnSpanAll); - newStyle->setDisplay(BLOCK); - - RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */); - newBox->setStyle(newStyle.release()); - return newBox; + if (isAnonymousColumnsBlock()) + return createAnonymousColumnsWithParentRenderer(parent); + if (isAnonymousColumnSpanBlock()) + return createAnonymousColumnSpanWithParentRenderer(parent); + return createAnonymousWithParentRendererAndDisplay(parent, style()->display()); } bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const @@ -6777,7 +6660,7 @@ LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit || (checkRegionBreaks && child->style()->regionBreakInside() == PBAVOID); if (!isUnsplittable) return logicalOffset; - LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : zeroLayoutUnit); + LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : ZERO_LAYOUT_UNIT); LayoutState* layoutState = view()->layoutState(); if (layoutState->m_columnInfo) layoutState->m_columnInfo->updateMinimumColumnHeight(childLogicalHeight); @@ -6876,7 +6759,7 @@ LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfter // When the child shifts to clear an item, its width can // change (because it has more available line width). // So go ahead and mark the item as dirty. - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); } if (childRenderBlock) { @@ -7072,20 +6955,6 @@ LayoutUnit RenderBlock::marginAfterForChild(const RenderBoxModelObject* child) c return child->marginBottom(); } -LayoutUnit RenderBlock::marginLogicalLeftForChild(const RenderBoxModelObject* child) const -{ - if (isHorizontalWritingMode()) - return child->marginLeft(); - return child->marginTop(); -} - -LayoutUnit RenderBlock::marginLogicalRightForChild(const RenderBoxModelObject* child) const -{ - if (isHorizontalWritingMode()) - return child->marginRight(); - return child->marginBottom(); -} - LayoutUnit RenderBlock::marginStartForChild(const RenderBoxModelObject* child) const { if (isHorizontalWritingMode()) @@ -7168,13 +7037,13 @@ void RenderBlock::setMarginAfterForChild(RenderBox* child, LayoutUnit margin) RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child) { - int childBeforePositive = 0; - int childBeforeNegative = 0; - int childAfterPositive = 0; - int childAfterNegative = 0; + LayoutUnit childBeforePositive = 0; + LayoutUnit childBeforeNegative = 0; + LayoutUnit childAfterPositive = 0; + LayoutUnit childAfterNegative = 0; - int beforeMargin = 0; - int afterMargin = 0; + LayoutUnit beforeMargin = 0; + LayoutUnit afterMargin = 0; RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0; @@ -7256,34 +7125,29 @@ inline void RenderBlock::FloatingObjects::clear() m_placedFloatsTree.clear(); m_leftObjectsCount = 0; m_rightObjectsCount = 0; - m_positionedObjectsCount = 0; } inline void RenderBlock::FloatingObjects::increaseObjectsCount(FloatingObject::Type type) { if (type == FloatingObject::FloatLeft) m_leftObjectsCount++; - else if (type == FloatingObject::FloatRight) + else m_rightObjectsCount++; - else - m_positionedObjectsCount++; } inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::Type type) { if (type == FloatingObject::FloatLeft) m_leftObjectsCount--; - else if (type == FloatingObject::FloatRight) - m_rightObjectsCount--; else - m_positionedObjectsCount--; + m_rightObjectsCount--; } inline RenderBlock::FloatingObjectInterval RenderBlock::FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject) { if (m_horizontalWritingMode) - return RenderBlock::FloatingObjectInterval(floatingObject->y(), floatingObject->maxY(), floatingObject); - return RenderBlock::FloatingObjectInterval(floatingObject->x(), floatingObject->maxX(), floatingObject); + return RenderBlock::FloatingObjectInterval(floatingObject->pixelSnappedY(), floatingObject->pixelSnappedMaxY(), floatingObject); + return RenderBlock::FloatingObjectInterval(floatingObject->pixelSnappedX(), floatingObject->pixelSnappedMaxX(), floatingObject); } void RenderBlock::FloatingObjects::addPlacedObject(FloatingObject* floatingObject) @@ -7371,6 +7235,45 @@ TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, c return constructTextRun(context, font, string.characters(), string.length(), style, expansion, flags); } +RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const RenderObject* parent, EDisplay display) +{ + // FIXME: Do we need to cover the new flex box here ? + // FIXME: Do we need to convert all our inline displays to block-type in the anonymous logic ? + EDisplay newDisplay; + RenderBlock* newBox = 0; + if (display == BOX || display == INLINE_BOX) { + newBox = new (parent->renderArena()) RenderDeprecatedFlexibleBox(parent->document() /* anonymous box */); + newDisplay = BOX; + } else { + newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */); + newDisplay = BLOCK; + } + + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), newDisplay); + newBox->setStyle(newStyle.release()); + return newBox; +} + +RenderBlock* RenderBlock::createAnonymousColumnsWithParentRenderer(const RenderObject* parent) +{ + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK); + newStyle->inheritColumnPropertiesFrom(parent->style()); + + RenderBlock* newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */); + newBox->setStyle(newStyle.release()); + return newBox; +} + +RenderBlock* RenderBlock::createAnonymousColumnSpanWithParentRenderer(const RenderObject* parent) +{ + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK); + newStyle->setColumnSpan(ColumnSpanAll); + + RenderBlock* newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */); + newBox->setStyle(newStyle.release()); + return newBox; +} + #ifndef NDEBUG void RenderBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj) const @@ -7388,7 +7291,7 @@ String ValueToString<int>::string(const int value) String ValueToString<RenderBlock::FloatingObject*>::string(const RenderBlock::FloatingObject* floatingObject) { - return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->x(), floatingObject->y(), floatingObject->maxX(), floatingObject->maxY()); + return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->pixelSnappedX(), floatingObject->pixelSnappedY(), floatingObject->pixelSnappedMaxX(), floatingObject->pixelSnappedMaxY()); } #endif diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h index cf2317348..2f6f4b6de 100644 --- a/Source/WebCore/rendering/RenderBlock.h +++ b/Source/WebCore/rendering/RenderBlock.h @@ -96,8 +96,7 @@ public: virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0); virtual void removeChild(RenderObject*); - enum BlockLayoutPass { NormalLayoutPass, PositionedFloatLayoutPass }; - virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0, BlockLayoutPass = NormalLayoutPass); + virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0); void insertPositionedObject(RenderBox*); void removePositionedObject(RenderBox*); @@ -166,6 +165,17 @@ public: { return logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(position), firstLine, 0); } + LayoutUnit pixelSnappedLogicalLeftOffsetForLine(LayoutUnit position, bool firstLine) const + { + return roundToInt(logicalLeftOffsetForLine(position, firstLine)); + } + LayoutUnit pixelSnappedLogicalRightOffsetForLine(LayoutUnit position, bool firstLine) const + { + // FIXME: Multicolumn layouts break carrying over subpixel values to the logical right offset because the lines may be shifted + // by a subpixel value for all but the first column. This can lead to the actual pixel snapped width of the column being off + // by one pixel when rendered versus layed out, which can result in the line being clipped. For now, we have to floor. + return floorToInt(logicalRightOffsetForLine(position, firstLine)); + } LayoutUnit startOffsetForLine(LayoutUnit position, bool firstLine) const { return style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(position, firstLine) @@ -177,17 +187,6 @@ public: : logicalWidth() - logicalRightOffsetForLine(position, firstLine); } - // FIXME: The implementation for these functions will change once we move to subpixel layout. See bug 60318. - int pixelSnappedLogicalRightOffsetForLine(LayoutUnit position, bool firstLine) const - { - return logicalRightOffsetForLine(position, logicalRightOffsetForContent(position), firstLine, 0); - } - - int pixelSnappedLogicalLeftOffsetForLine(LayoutUnit position, bool firstLine) const - { - return roundToInt(logicalLeftOffsetForLine(position, logicalLeftOffsetForContent(position), firstLine, 0)); - } - LayoutUnit startAlignedOffsetForLine(RenderBox* child, LayoutUnit position, bool firstLine); LayoutUnit textIndentOffset() const; @@ -210,6 +209,8 @@ public: LayoutRect logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo*); void getSelectionGapInfo(SelectionState, bool& leftGap, bool& rightGap); + RenderBlock* blockBeforeWithinSelectionRoot(LayoutSize& offset) const; + LayoutRect logicalRectToPhysicalRect(const LayoutPoint& physicalPosition, const LayoutRect& logicalRect); // Helper methods for computing line counts and heights for line counts. @@ -233,12 +234,14 @@ public: using RenderBoxModelObject::continuation; using RenderBoxModelObject::setContinuation; - // This function is a convenience helper for creating an anonymous block that inherits its - // style from this RenderBlock. - RenderBlock* createAnonymousBlock(bool isFlexibleBox = false) const; - RenderBlock* createAnonymousColumnsBlock() const; - RenderBlock* createAnonymousColumnSpanBlock() const; - RenderBlock* createAnonymousBlockWithSameTypeAs(RenderBlock* otherAnonymousBlock) const; + static RenderBlock* createAnonymousWithParentRendererAndDisplay(const RenderObject*, EDisplay = BLOCK); + static RenderBlock* createAnonymousColumnsWithParentRenderer(const RenderObject*); + static RenderBlock* createAnonymousColumnSpanWithParentRenderer(const RenderObject*); + RenderBlock* createAnonymousBlock(EDisplay display = BLOCK) const { return createAnonymousWithParentRendererAndDisplay(this, display); } + RenderBlock* createAnonymousColumnsBlock() const { return createAnonymousColumnsWithParentRenderer(this); } + RenderBlock* createAnonymousColumnSpanBlock() const { return createAnonymousColumnSpanWithParentRenderer(this); } + + virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const OVERRIDE; static void appendRunsForObject(BidiRunList<BidiRun>&, int start, int end, RenderObject*, InlineBidiResolver&); @@ -255,13 +258,13 @@ public: unsigned columnCount(ColumnInfo*) const; LayoutRect columnRectAt(ColumnInfo*, unsigned) const; - LayoutUnit paginationStrut() const { return m_rareData ? m_rareData->m_paginationStrut : zeroLayoutUnit; } + LayoutUnit paginationStrut() const { return m_rareData ? m_rareData->m_paginationStrut : ZERO_LAYOUT_UNIT; } void setPaginationStrut(LayoutUnit); // The page logical offset is the object's offset from the top of the page in the page progression // direction (so an x-offset in vertical text and a y-offset for horizontal text). - LayoutUnit pageLogicalOffset() const { return m_rareData ? m_rareData->m_pageLogicalOffset : zeroLayoutUnit; } - void setPageLogicalOffset(int); + LayoutUnit pageLogicalOffset() const { return m_rareData ? m_rareData->m_pageLogicalOffset : ZERO_LAYOUT_UNIT; } + void setPageLogicalOffset(LayoutUnit); RootInlineBox* lineGridBox() const { return m_rareData ? m_rareData->m_lineGridBox : 0; } void setLineGridBox(RootInlineBox* box) @@ -279,15 +282,12 @@ public: LayoutUnit logicalWidthForChild(const RenderBox* child) { return isHorizontalWritingMode() ? child->width() : child->height(); } LayoutUnit logicalHeightForChild(const RenderBox* child) { return isHorizontalWritingMode() ? child->height() : child->width(); } LayoutUnit logicalTopForChild(const RenderBox* child) { return isHorizontalWritingMode() ? child->y() : child->x(); } - LayoutUnit logicalLeftForChild(const RenderBox* child) { return isHorizontalWritingMode() ? child->x() : child->y(); } void setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta); void setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta); LayoutUnit marginBeforeForChild(const RenderBoxModelObject* child) const; LayoutUnit marginAfterForChild(const RenderBoxModelObject* child) const; LayoutUnit marginStartForChild(const RenderBoxModelObject* child) const; LayoutUnit marginEndForChild(const RenderBoxModelObject* child) const; - LayoutUnit marginLogicalLeftForChild(const RenderBoxModelObject* child) const; - LayoutUnit marginLogicalRightForChild(const RenderBoxModelObject* child) const; void setMarginStartForChild(RenderBox* child, LayoutUnit); void setMarginEndForChild(RenderBox* child, LayoutUnit); void setMarginBeforeForChild(RenderBox* child, LayoutUnit); @@ -371,8 +371,7 @@ public: void setStaticInlinePositionForChild(RenderBox*, LayoutUnit blockOffset, LayoutUnit inlinePosition); - LayoutUnit computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, - LayoutUnit childLogicalWidth, RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = 0); + LayoutUnit computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = 0); #ifndef NDEBUG void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0) const; @@ -381,32 +380,6 @@ public: protected: virtual void willBeDestroyed(); - void updateScrollInfoAfterLayout(); - - // These functions are only used internally to manipulate the render tree structure via remove/insert/appendChildNode. - // Since they are typically called only to move objects around within anonymous blocks (which only have layers in - // the case of column spans), the default for fullRemoveInsert is false rather than true. - void moveChildTo(RenderBlock* to, RenderObject* child, bool fullRemoveInsert = false) - { - return moveChildTo(to, child, 0, fullRemoveInsert); - } - void moveChildTo(RenderBlock* toBlock, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert = false); - void moveAllChildrenTo(RenderBlock* toBlock, bool fullRemoveInsert = false) - { - return moveAllChildrenTo(toBlock, 0, fullRemoveInsert); - } - void moveAllChildrenTo(RenderBlock* toBlock, RenderObject* beforeChild, bool fullRemoveInsert = false) - { - return moveChildrenTo(toBlock, firstChild(), 0, beforeChild, fullRemoveInsert); - } - // Move all of the kids from |startChild| up to but excluding |endChild|. 0 can be passed as the endChild to denote - // that all the kids from |startChild| onwards should be added. - void moveChildrenTo(RenderBlock* toBlock, RenderObject* startChild, RenderObject* endChild, bool fullRemoveInsert = false) - { - return moveChildrenTo(toBlock, startChild, endChild, 0, fullRemoveInsert); - } - void moveChildrenTo(RenderBlock* toBlock, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert = false); - LayoutUnit maxPositiveMarginBefore() const { return m_rareData ? m_rareData->m_margins.positiveMarginBefore() : RenderBlockRareData::positiveMarginBeforeDefault(this); } LayoutUnit maxNegativeMarginBefore() const { return m_rareData ? m_rareData->m_margins.negativeMarginBefore() : RenderBlockRareData::negativeMarginBeforeDefault(this); } LayoutUnit maxPositiveMarginAfter() const { return m_rareData ? m_rareData->m_margins.positiveMarginAfter() : RenderBlockRareData::positiveMarginAfterDefault(this); } @@ -426,7 +399,7 @@ protected: virtual void layout(); - bool layoutPositionedObjects(bool relayoutChildren); + void layoutPositionedObjects(bool relayoutChildren); virtual void paint(PaintInfo&, const LayoutPoint&); virtual void paintObject(PaintInfo&, const LayoutPoint&); @@ -480,6 +453,7 @@ protected: { LayoutUnit repaintLogicalTop = 0; LayoutUnit repaintLogicalBottom = 0; + clearFloats(); layoutInlineChildren(true, repaintLogicalTop, repaintLogicalBottom); } #endif @@ -529,6 +503,9 @@ private: // Called to lay out the legend for a fieldset or the ruby text of a ruby run. virtual RenderObject* layoutSpecialExcludedChild(bool /*relayoutChildren*/) { return 0; } + void createFirstLetterRenderer(RenderObject* firstLetterBlock, RenderObject* currentChild); + void updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer); + struct FloatWithRect { FloatWithRect(RenderBox* f) : object(f) @@ -545,15 +522,14 @@ private: struct FloatingObject { WTF_MAKE_NONCOPYABLE(FloatingObject); WTF_MAKE_FAST_ALLOCATED; public: - // FloatLeftRight is a mask to query for both left and right but not positioned. - // FloatAll is a mask to query for all types of floats. - enum Type { FloatLeft = 1, FloatRight = 2, FloatLeftRight = 3, FloatPositioned = 4, FloatAll = 7 }; + // Note that Type uses bits so you can use FloatLeftRight as a mask to query for both left and right. + enum Type { FloatLeft = 1, FloatRight = 2, FloatLeftRight = 3 }; FloatingObject(EFloat type) : m_renderer(0) , m_originatingLine(0) , m_paginationStrut(0) - , m_shouldPaint(false) + , m_shouldPaint(true) , m_isDescendant(false) , m_isPlaced(false) #ifndef NDEBUG @@ -564,9 +540,7 @@ private: if (type == LeftFloat) m_type = FloatLeft; else if (type == RightFloat) - m_type = FloatRight; - else if (type == PositionedFloat) - m_type = FloatPositioned; + m_type = FloatRight; } FloatingObject(Type type, const LayoutRect& frameRect) @@ -575,7 +549,7 @@ private: , m_frameRect(frameRect) , m_paginationStrut(0) , m_type(type) - , m_shouldPaint(type != FloatPositioned) + , m_shouldPaint(true) , m_isDescendant(false) , m_isPlaced(true) #ifndef NDEBUG @@ -597,13 +571,12 @@ private: LayoutUnit width() const { return m_frameRect.width(); } LayoutUnit height() const { return m_frameRect.height(); } - // FIXME: The implementation for these functions will change once we move to subpixel layout. See bug 60318. - int pixelSnappedX() const { return x(); } - int pixelSnappedMaxX() const { return maxX(); } - int pixelSnappedY() const { return y(); } - int pixelSnappedMaxY() const { return maxY(); } - int pixelSnappedWidth() const { return width(); } - int pixelSnappedHeight() const { return height(); } + int pixelSnappedX() const { ASSERT(isPlaced()); return m_frameRect.pixelSnappedX(); } + int pixelSnappedMaxX() const { ASSERT(isPlaced()); return m_frameRect.pixelSnappedMaxX(); } + int pixelSnappedY() const { ASSERT(isPlaced()); return m_frameRect.pixelSnappedY(); } + int pixelSnappedMaxY() const { ASSERT(isPlaced()); return m_frameRect.pixelSnappedMaxY(); } + int pixelSnappedWidth() const { return m_frameRect.pixelSnappedWidth(); } + int pixelSnappedHeight() const { return m_frameRect.pixelSnappedHeight(); } void setX(LayoutUnit x) { ASSERT(!isInPlacedTree()); m_frameRect.setX(x); } void setY(LayoutUnit y) { ASSERT(!isInPlacedTree()); m_frameRect.setY(y); } @@ -618,16 +591,23 @@ private: void setIsInPlacedTree(bool value) { m_isInPlacedTree = value; } #endif + bool shouldPaint() const { return m_shouldPaint; } + void setShouldPaint(bool shouldPaint) { m_shouldPaint = shouldPaint; } + bool isDescendant() const { return m_isDescendant; } + void setIsDescendant(bool isDescendant) { m_isDescendant = isDescendant; } + RenderBox* m_renderer; RootInlineBox* m_originatingLine; LayoutRect m_frameRect; int m_paginationStrut; - unsigned m_type : 3; // Type (left/right aligned or positioned) - bool m_shouldPaint : 1; - bool m_isDescendant : 1; - bool m_isPlaced : 1; + + private: + unsigned m_type : 2; // Type (left or right aligned) + unsigned m_shouldPaint : 1; + unsigned m_isDescendant : 1; + unsigned m_isPlaced : 1; #ifndef NDEBUG - bool m_isInPlacedTree : 1; + unsigned m_isInPlacedTree : 1; #endif }; @@ -759,23 +739,18 @@ private: // Returns true if and only if it has positioned any floats. bool positionNewFloats(); - bool hasPositionedFloats() const { return m_hasPositionedFloats; } - void addPositionedFloats(); - bool positionedFloatsNeedRelayout(); + void clearFloats(); - void clearFloats(BlockLayoutPass); LayoutUnit getClearDelta(RenderBox* child, LayoutUnit yPos); virtual bool avoidsFloats() const; - bool hasOverhangingFloats() { return parent() && !hasColumns() && containsFloats() && lowestFloatLogicalBottomIncludingPositionedFloats() > logicalHeight(); } + bool hasOverhangingFloats() { return parent() && !hasColumns() && containsFloats() && lowestFloatLogicalBottom() > logicalHeight(); } bool hasOverhangingFloat(RenderBox*); void addIntrudingFloats(RenderBlock* prev, LayoutUnit xoffset, LayoutUnit yoffset); LayoutUnit addOverhangingFloats(RenderBlock* child, bool makeChildPaintOtherFloats); - LayoutUnit lowestFloatLogicalBottom() const { return lowestFloatLogicalBottom(FloatingObject::FloatLeftRight); } - LayoutUnit lowestFloatLogicalBottomIncludingPositionedFloats() const { return lowestFloatLogicalBottom(FloatingObject::FloatAll); } - LayoutUnit lowestFloatLogicalBottom(FloatingObject::Type) const; + LayoutUnit lowestFloatLogicalBottom(FloatingObject::Type = FloatingObject::FloatLeftRight) const; LayoutUnit nextFloatLogicalBottomBelow(LayoutUnit) const; virtual bool hitTestColumns(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); @@ -814,7 +789,7 @@ private: LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo*); LayoutUnit logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position); LayoutUnit logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position); - + virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const; virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; @@ -844,8 +819,8 @@ private: bool expandsToEncloseOverhangingFloats() const; - RenderObject* splitAnonymousBlocksAroundChild(RenderObject* beforeChild); - RenderObject* splitTablePartsAroundChild(RenderObject* beforeChild); + void updateScrollInfoAfterLayout(); + void splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock, RenderBlock* middleBlock, RenderObject* beforeChild, RenderBoxModelObject* oldCont); void splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, @@ -983,6 +958,8 @@ protected: virtual bool requiresColumns(int desiredColumnCount) const; + virtual bool recomputeLogicalWidth(); + public: LayoutUnit offsetFromLogicalTopOfFirstPage() const; RenderRegion* regionAtBlockOffset(LayoutUnit) const; @@ -1034,7 +1011,6 @@ protected: : m_placedFloatsTree(UninitializedTree) , m_leftObjectsCount(0) , m_rightObjectsCount(0) - , m_positionedObjectsCount(0) , m_horizontalWritingMode(horizontalWritingMode) , m_renderer(renderer) { @@ -1049,7 +1025,6 @@ protected: bool hasLeftObjects() const { return m_leftObjectsCount > 0; } bool hasRightObjects() const { return m_rightObjectsCount > 0; } - bool hasPositionedObjects() const { return m_positionedObjectsCount > 0; } const FloatingObjectSet& set() const { return m_set; } const FloatingObjectTree& placedFloatsTree() { @@ -1071,7 +1046,6 @@ protected: FloatingObjectTree m_placedFloatsTree; unsigned m_leftObjectsCount; unsigned m_rightObjectsCount; - unsigned m_positionedObjectsCount; bool m_horizontalWritingMode; const RenderBlock* m_renderer; }; @@ -1122,10 +1096,9 @@ protected: 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>. - mutable signed m_lineHeight : 29; - bool m_beingDestroyed : 1; - bool m_hasPositionedFloats : 1; - bool m_hasMarkupTruncation : 1; + mutable signed m_lineHeight : 30; + unsigned m_beingDestroyed : 1; + unsigned m_hasMarkupTruncation : 1; // RenderRubyBase objects need to be able to split and merge, moving their children around // (calling moveChildTo, moveAllChildrenTo, and makeChildrenNonInline). diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index e98db5c79..bceb24ac7 100755 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -123,18 +123,18 @@ inline void LineWidth::updateAvailableWidth() inline void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(RenderBlock::FloatingObject* newFloat) { - int height = m_block->logicalHeight(); + LayoutUnit height = m_block->logicalHeight(); if (height < m_block->logicalTopForFloat(newFloat) || height >= m_block->logicalBottomForFloat(newFloat)) return; if (newFloat->type() == RenderBlock::FloatingObject::FloatLeft) { m_left = m_block->pixelSnappedLogicalRightForFloat(newFloat); if (m_isFirstLine && m_block->style()->isLeftToRightDirection()) - m_left += m_block->textIndentOffset(); + m_left += floorToInt(m_block->textIndentOffset()); } else { m_right = m_block->pixelSnappedLogicalLeftForFloat(newFloat); if (m_isFirstLine && !m_block->style()->isLeftToRightDirection()) - m_right -= m_block->textIndentOffset(); + m_right -= floorToInt(m_block->textIndentOffset()); } computeAvailableWidthFromLeftAndRight(); @@ -159,8 +159,8 @@ void LineWidth::fitBelowFloats() ASSERT(!m_committedWidth); ASSERT(!fitsOnLine()); - int floatLogicalBottom; - int lastFloatLogicalBottom = m_block->logicalHeight(); + LayoutUnit floatLogicalBottom; + LayoutUnit lastFloatLogicalBottom = m_block->logicalHeight(); float newLineWidth = m_availableWidth; float newLineLeft = m_left; float newLineRight = m_right; @@ -522,7 +522,7 @@ RootInlineBox* RenderBlock::constructLine(BidiRunList<BidiRun>& bidiRuns, const InlineTextBox* text = toInlineTextBox(box); text->setStart(r->m_start); text->setLen(r->m_stop - r->m_start); - text->m_dirOverride = r->dirOverride(visuallyOrdered); + text->setDirOverride(r->dirOverride(visuallyOrdered)); if (r->m_hasHyphen) text->setHasHyphen(true); } @@ -654,7 +654,7 @@ static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru glyphOverflow.computeBounds = true; } - int hyphenWidth = 0; + LayoutUnit hyphenWidth = 0; if (toInlineTextBox(run->m_box)->hasHyphen()) { const Font& font = renderer->style(lineInfo.isFirstLine())->font(); hyphenWidth = measureHyphenWidth(renderer, font); @@ -662,14 +662,14 @@ static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru run->m_box->setLogicalWidth(renderer->width(run->m_start, run->m_stop - run->m_start, xPos, lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow) + hyphenWidth); if (!fallbackFonts.isEmpty()) { ASSERT(run->m_box->isText()); - GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first; + GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).iterator; ASSERT(it->second.first.isEmpty()); copyToVector(fallbackFonts, it->second.first); run->m_box->parent()->clearDescendantsHaveSameLineHeightAndBaseline(); } if ((glyphOverflow.top || glyphOverflow.bottom || glyphOverflow.left || glyphOverflow.right)) { ASSERT(run->m_box->isText()); - GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first; + GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).iterator; it->second.second = glyphOverflow; run->m_box->clearKnownToHaveNoOverflow(); } @@ -1096,8 +1096,8 @@ public: void updateRepaintRangeFromBox(RootInlineBox* box, LayoutUnit paginationDelta = 0) { m_usesRepaintBounds = true; - m_repaintLogicalTop = min(m_repaintLogicalTop, box->logicalTopVisualOverflow() + min(paginationDelta, zeroLayoutUnit)); - m_repaintLogicalBottom = max(m_repaintLogicalBottom, box->logicalBottomVisualOverflow() + max(paginationDelta, zeroLayoutUnit)); + m_repaintLogicalTop = min(m_repaintLogicalTop, box->logicalTopVisualOverflow() + min(paginationDelta, ZERO_LAYOUT_UNIT)); + m_repaintLogicalBottom = max(m_repaintLogicalBottom, box->logicalBottomVisualOverflow() + max(paginationDelta, ZERO_LAYOUT_UNIT)); } bool endLineMatched() const { return m_endLineMatched; } @@ -1109,8 +1109,8 @@ public: LineInfo& lineInfo() { return m_lineInfo; } const LineInfo& lineInfo() const { return m_lineInfo; } - int endLineLogicalTop() const { return m_endLineLogicalTop; } - void setEndLineLogicalTop(int logicalTop) { m_endLineLogicalTop = logicalTop; } + LayoutUnit endLineLogicalTop() const { return m_endLineLogicalTop; } + void setEndLineLogicalTop(LayoutUnit logicalTop) { m_endLineLogicalTop = logicalTop; } RootInlineBox* endLine() const { return m_endLine; } void setEndLine(RootInlineBox* line) { m_endLine = line; } @@ -1129,7 +1129,7 @@ private: RootInlineBox* m_endLine; LineInfo m_lineInfo; unsigned m_floatIndex; - int m_endLineLogicalTop; + LayoutUnit m_endLineLogicalTop; bool m_endLineMatched; bool m_checkForFloatsFromLastLine; @@ -1171,8 +1171,7 @@ void RenderBlock::layoutRunsAndFloats(LineLayoutState& layoutState, bool hasInli // determineStartPosition can change the fullLayout flag we have to do this here. Failure to call // determineStartPosition first will break fast/repaint/line-flow-with-floats-9.html. if (layoutState.isFullLayout() && hasInlineChild && !selfNeedsLayout()) { - setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like - // we're supposed to. + setNeedsLayout(true, MarkOnlyThis); // Mark as needing a full layout to force us to repaint. RenderView* v = view(); if (v && !v->doingFullRepaint() && hasLayer()) { // Because we waited until we were already inside layout to discover @@ -1400,19 +1399,19 @@ void RenderBlock::linkToEndLineIfNeeded(LineLayoutState& layoutState) // This has to be done before adding in the bottom border/padding, or the float will // include the padding incorrectly. -dwh if (layoutState.checkForFloatsFromLastLine()) { - int bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow(); - int bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow(); + LayoutUnit bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow(); + LayoutUnit bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow(); TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this); m_lineBoxes.appendLineBox(trailingFloatsLineBox); trailingFloatsLineBox->setConstructed(); GlyphOverflowAndFallbackFontsMap textBoxDataMap; VerticalPositionCache verticalPositionCache; - int blockLogicalHeight = logicalHeight(); + LayoutUnit blockLogicalHeight = logicalHeight(); trailingFloatsLineBox->alignBoxesInBlockDirection(blockLogicalHeight, textBoxDataMap, verticalPositionCache); trailingFloatsLineBox->setLineTopBottomPositions(blockLogicalHeight, blockLogicalHeight, blockLogicalHeight, blockLogicalHeight); trailingFloatsLineBox->setPaginatedLineWidth(availableLogicalWidthForContent(blockLogicalHeight)); - IntRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight); - IntRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight); + LayoutRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight); + LayoutRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight); trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom()); } @@ -1487,11 +1486,11 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repain RenderBox* box = toRenderBox(o); if (relayoutChildren || box->hasRelativeDimensions()) - o->setChildNeedsLayout(true, false); + o->setChildNeedsLayout(true, MarkOnlyThis); // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths. if (relayoutChildren && box->needsPreferredWidthsRecalculation()) - o->setPreferredLogicalWidthsDirty(true, false); + o->setPreferredLogicalWidthsDirty(true, MarkOnlyThis); if (o->isPositioned()) o->containingBlock()->insertPositionedObject(box); @@ -1517,7 +1516,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repain // Expand the last line to accommodate Ruby and emphasis marks. int lastLineAnnotationsAdjustment = 0; if (lastRootBox()) { - int lowestAllowedPosition = max(lastRootBox()->lineBottom(), logicalHeight() + paddingAfter()); + LayoutUnit lowestAllowedPosition = max(lastRootBox()->lineBottom(), logicalHeight() + paddingAfter()); if (!style()->isFlippedLinesWritingMode()) lastLineAnnotationsAdjustment = lastRootBox()->computeUnderAnnotationAdjustment(lowestAllowedPosition); else @@ -1557,7 +1556,7 @@ void RenderBlock::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRe LayoutUnit floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x(); LayoutUnit floatHeight = isHorizontalWritingMode() ? max(floats[floatIndex].rect.height(), newSize.height()) : max(floats[floatIndex].rect.width(), newSize.width()); - floatHeight = min(floatHeight, numeric_limits<LayoutUnit>::max() - floatTop); + floatHeight = min(floatHeight, MAX_LAYOUT_UNIT - floatTop); line->markDirty(); markLinesDirtyInBlockRange(line->lineBottomWithLeading(), floatTop + floatHeight, line); floats[floatIndex].rect.setSize(newSize); @@ -1758,7 +1757,7 @@ bool RenderBlock::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutState while (RootInlineBox* nextLine = lastLine->nextRootBox()) lastLine = nextLine; - LayoutUnit logicalBottom = lastLine->lineBottomWithLeading() + abs(lineDelta); + LayoutUnit logicalBottom = lastLine->lineBottomWithLeading() + absoluteValue(lineDelta); const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); FloatingObjectSetIterator end = floatingObjectSet.end(); @@ -1948,6 +1947,7 @@ static inline float textWidth(RenderText* text, unsigned from, unsigned len, con run.setCharactersLength(text->textLength() - from); ASSERT(run.charactersLength() >= run.length()); + run.setCharacterScanForCodePath(!text->canUseSimpleFontCodePath()); run.setAllowTabs(!collapseWhiteSpace); run.setXPos(xPos); return font.width(run); @@ -2666,7 +2666,7 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol void RenderBlock::addOverflowFromInlineChildren() { - LayoutUnit endPadding = hasOverflowClip() ? paddingEnd() : zeroLayoutUnit; + LayoutUnit endPadding = hasOverflowClip() ? paddingEnd() : ZERO_LAYOUT_UNIT; // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to. if (hasOverflowClip() && !endPadding && node() && node()->rendererIsEditable() && node() == node()->rootEditableElement() && style()->isLeftToRightDirection()) endPadding = 1; @@ -2690,8 +2690,8 @@ void RenderBlock::checkLinesForTextOverflow() const Font& font = style()->font(); DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1)); const Font& firstLineFont = firstLineStyle()->font(); - LayoutUnit firstLineEllipsisWidth = firstLineFont.width(constructTextRun(this, firstLineFont, &horizontalEllipsis, 1, firstLineStyle())); - LayoutUnit ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style())); + int firstLineEllipsisWidth = firstLineFont.width(constructTextRun(this, firstLineFont, &horizontalEllipsis, 1, firstLineStyle())); + int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style())); // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see // if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and @@ -2750,7 +2750,7 @@ bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObjec RenderBox* o = f->m_renderer; setLogicalTopForChild(o, logicalTopForChild(o) + marginBeforeForChild(o) + paginationStrut); if (o->isRenderBlock()) - toRenderBlock(o)->setChildNeedsLayout(true, false); + toRenderBlock(o)->setChildNeedsLayout(true, MarkOnlyThis); o->layoutIfNeeded(); // Save the old logical top before calling removePlacedObject which will set // isPlaced to false. Otherwise it will trigger an assert in logicalTopForFloat. diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index bafdc376a..b906ec94d 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -253,19 +253,25 @@ void RenderBox::willBeDestroyed() if (styleToUse && (styleToUse->logicalHeight().isPercent() || styleToUse->logicalMinHeight().isPercent() || styleToUse->logicalMaxHeight().isPercent())) RenderBlock::removePercentHeightDescendant(this); - // If this renderer is owning renderer for the frameview's custom scrollbars, - // we need to clear it from the scrollbar. See webkit bug 64737. - if (styleToUse && styleToUse->hasPseudoStyle(SCROLLBAR) && frame() && frame()->view()) - frame()->view()->clearOwningRendererForCustomScrollbars(this); + if (styleToUse) { + if (RenderView* view = this->view()) { + if (FrameView* frameView = view->frameView()) { + // If this renderer is owning renderer for the FrameView's custom scrollbars, + // we need to clear it from the scrollbar. See webkit bug 64737. + if (styleToUse->hasPseudoStyle(SCROLLBAR)) + frameView->clearOwningRendererForCustomScrollbars(this); + + if (styleToUse->position() == FixedPosition) + frameView->removeFixedObject(); + } + } + } // If the following assertion fails, logicalHeight()/logicalMinHeight()/ // logicalMaxHeight() values are changed from a percent value to a non-percent // value during laying out. It causes a use-after-free bug. ASSERT(!RenderBlock::hasPercentHeightDescendant(this)); - if (hasOverflowClip() && everHadLayout() && !hasLayer()) - clearCachedSizeForOverflowClip(); - RenderBoxModelObject::willBeDestroyed(); } @@ -363,7 +369,7 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the // new zoomed coordinate space. - if (hasOverflowClipWithLayer() && oldStyle && newStyle && oldStyle->effectiveZoom() != newStyle->effectiveZoom()) { + if (hasOverflowClip() && oldStyle && newStyle && oldStyle->effectiveZoom() != newStyle->effectiveZoom()) { if (int left = layer()->scrollXOffset()) { left = (left / oldStyle->effectiveZoom()) * newStyle->effectiveZoom(); layer()->scrollToXOffset(left); @@ -419,7 +425,7 @@ void RenderBox::updateBoxModelInfoFromStyle() setHasBoxDecorations(true); setPositioned(styleToUse->isPositioned()); - setFloating(styleToUse->isFloating() && (!isPositioned() || styleToUse->floating() == PositionedFloat)); + setFloating(!isPositioned() && styleToUse->isFloating()); // We also handle <body> and <html>, whose overflow applies to the viewport. if (styleToUse->overflowX() != OVISIBLE && !isRootObject && (isRenderBlock() || isTableRow() || isTableSection())) { @@ -466,10 +472,6 @@ void RenderBox::layout() child = child->nextSibling(); } statePusher.pop(); - - if (hasOverflowClip() && !hasLayer()) - updateCachedSizeForOverflowClip(); - setNeedsLayout(false); } @@ -487,53 +489,53 @@ LayoutUnit RenderBox::clientHeight() const int RenderBox::pixelSnappedClientWidth() const { - return snapSizeToPixel(clientWidth(), clientLeft()); + return snapSizeToPixel(clientWidth(), x() + clientLeft()); } int RenderBox::pixelSnappedClientHeight() const { - return snapSizeToPixel(clientHeight(), clientTop()); + return snapSizeToPixel(clientHeight(), y() + clientTop()); } int RenderBox::scrollWidth() const { - if (hasOverflowClipWithLayer()) + if (hasOverflowClip()) return layer()->scrollWidth(); // For objects with visible overflow, this matches IE. // FIXME: Need to work right with writing modes. if (style()->isLeftToRightDirection()) - return max(clientWidth(), maxXLayoutOverflow() - borderLeft()); - return clientWidth() - min(0, minXLayoutOverflow() - borderLeft()); + return snapSizeToPixel(max(clientWidth(), maxXLayoutOverflow() - borderLeft()), clientLeft()); + return clientWidth() - min(ZERO_LAYOUT_UNIT, minXLayoutOverflow() - borderLeft()); } int RenderBox::scrollHeight() const { - if (hasOverflowClipWithLayer()) + if (hasOverflowClip()) return layer()->scrollHeight(); // For objects with visible overflow, this matches IE. // FIXME: Need to work right with writing modes. - return max(pixelSnappedClientHeight(), maxYLayoutOverflow() - borderTop()); + return snapSizeToPixel(max(clientHeight(), maxYLayoutOverflow() - borderTop()), clientTop()); } int RenderBox::scrollLeft() const { - return hasOverflowClipWithLayer() ? layer()->scrollXOffset() : 0; + return hasOverflowClip() ? layer()->scrollXOffset() : 0; } int RenderBox::scrollTop() const { - return hasOverflowClipWithLayer() ? layer()->scrollYOffset() : 0; + return hasOverflowClip() ? layer()->scrollYOffset() : 0; } void RenderBox::setScrollLeft(int newLeft) { - if (hasOverflowClipWithLayer()) + if (hasOverflowClip()) layer()->scrollToXOffset(newLeft, RenderLayer::ScrollOffsetClamped); } void RenderBox::setScrollTop(int newTop) { - if (hasOverflowClipWithLayer()) + if (hasOverflowClip()) layer()->scrollToYOffset(newTop, RenderLayer::ScrollOffsetClamped); } @@ -554,9 +556,9 @@ void RenderBox::updateLayerTransform() layer()->updateTransform(); } -LayoutRect RenderBox::absoluteContentBox() const +IntRect RenderBox::absoluteContentBox() const { - LayoutRect rect = contentBoxRect(); + IntRect rect = pixelSnappedIntRect(contentBoxRect()); FloatPoint absPos = localToAbsolute(FloatPoint()); rect.move(absPos.x(), absPos.y()); return rect; @@ -622,9 +624,10 @@ int RenderBox::reflectionOffset() const { if (!style()->boxReflect()) return 0; + RenderView* renderView = view(); if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight) - return style()->boxReflect()->offset().calcValue(borderBoxRect().width()); - return style()->boxReflect()->offset().calcValue(borderBoxRect().height()); + return valueForLength(style()->boxReflect()->offset(), borderBoxRect().width(), renderView); + return valueForLength(style()->boxReflect()->offset(), borderBoxRect().height(), renderView); } LayoutRect RenderBox::reflectedRect(const LayoutRect& r) const @@ -658,13 +661,13 @@ bool RenderBox::fixedElementLaysOutRelativeToFrame(Frame* frame, FrameView* fram bool RenderBox::includeVerticalScrollbarSize() const { - return hasOverflowClipWithLayer() && !layer()->hasOverlayScrollbars() + return hasOverflowClip() && !layer()->hasOverlayScrollbars() && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO); } bool RenderBox::includeHorizontalScrollbarSize() const { - return hasOverflowClipWithLayer() && !layer()->hasOverlayScrollbars() + return hasOverflowClip() && !layer()->hasOverlayScrollbars() && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO); } @@ -756,56 +759,15 @@ bool RenderBox::needsPreferredWidthsRecalculation() const IntSize RenderBox::scrolledContentOffset() const { ASSERT(hasOverflowClip()); - - if (hasLayer()) - return layer()->scrolledContentOffset(); - - // If we have no layer, it means that we have no overflowing content as we lazily - // allocate it on demand. Thus we don't have any scroll offset. - ASSERT(!requiresLayerForOverflowClip()); - return LayoutSize(); -} - -typedef HashMap<const RenderBox*, LayoutSize> RendererSizeCache; -static RendererSizeCache& cachedSizeForOverflowClipMap() -{ - DEFINE_STATIC_LOCAL(RendererSizeCache, cachedSizeForOverflowClipMap, ()); - return cachedSizeForOverflowClipMap; + ASSERT(hasLayer()); + return layer()->scrolledContentOffset(); } -IntSize RenderBox::cachedSizeForOverflowClip() const +LayoutSize RenderBox::cachedSizeForOverflowClip() const { ASSERT(hasOverflowClip()); - if (hasLayer()) - return layer()->size(); - - ASSERT(!requiresLayerForOverflowClip()); - RendererSizeCache::iterator it = cachedSizeForOverflowClipMap().find(this); - if (it == cachedSizeForOverflowClipMap().end()) - return LayoutSize(); - - return it->second; -} - -void RenderBox::updateCachedSizeForOverflowClip() -{ - ASSERT(hasOverflowClip()); - ASSERT(!requiresLayerForOverflowClip()); - ASSERT(!hasLayer()); - - cachedSizeForOverflowClipMap().set(this, size()); -} - -void RenderBox::clearCachedSizeForOverflowClip() -{ - ASSERT(hasOverflowClip()); - ASSERT(!requiresLayerForOverflowClip()); - ASSERT(!hasLayer()); - - // FIXME: We really would like to enable this ASSERT. However the current updateScrollInfoAfterLayout - // is not bullet-proof and it triggers in non-obvious ways under NRWT. - // ASSERT(cachedSizeForOverflowClipMap().contains(this)); - cachedSizeForOverflowClipMap().remove(this); + ASSERT(hasLayer()); + return layer()->size(); } LayoutUnit RenderBox::minPreferredLogicalWidth() const @@ -991,7 +953,7 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai // To avoid the background color bleeding out behind the border, we'll render background and border // into a transparency layer, and then clip that in one go (which requires setting up the clip before // beginning the layer). - RoundedRect border = style()->getRoundedBorderFor(paintRect); + RoundedRect border = style()->getRoundedBorderFor(paintRect, view()); stateSaver.save(); paintInfo.context->addRoundedRectClip(border); paintInfo.context->beginTransparencyLayer(1); @@ -999,17 +961,18 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai // If we have a native theme appearance, paint that before painting our background. // The theme will tell us whether or not we should also paint the CSS background. - bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, paintRect); + IntRect snappedPaintRect(pixelSnappedIntRect(paintRect)); + bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, snappedPaintRect); if (!themePainted) { paintBackground(paintInfo, paintRect, bleedAvoidance); if (style()->hasAppearance()) - theme()->paintDecorations(this, paintInfo, pixelSnappedIntRect(paintRect)); + theme()->paintDecorations(this, paintInfo, snappedPaintRect); } paintBoxShadow(paintInfo, paintRect, style(), Inset); // The theme will tell us whether or not we should also paint the CSS border. - if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, pixelSnappedIntRect(paintRect)))) && style()->hasBorder()) + if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, snappedPaintRect))) && style()->hasBorder()) paintBorder(paintInfo, paintRect, style(), bleedAvoidance); if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) @@ -1049,11 +1012,12 @@ void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& pa // Figure out if we need to push a transparency layer to render our mask. bool pushTransparencyLayer = false; bool compositedMask = hasLayer() && layer()->hasCompositedMask(); + bool flattenCompositingLayers = view()->frameView() && view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers; CompositeOperator compositeOp = CompositeSourceOver; bool allMaskImagesLoaded = true; - if (!compositedMask) { + if (!compositedMask || flattenCompositingLayers) { pushTransparencyLayer = true; StyleImage* maskBoxImage = style()->maskBoxImage().image(); const FillLayer* maskLayers = style()->maskLayers(); @@ -1158,7 +1122,7 @@ void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*) #if USE(ACCELERATED_COMPOSITING) if (hasLayer() && layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers())) - layer()->contentChanged(RenderLayer::MaskImageChanged); + layer()->contentChanged(MaskImageChanged); #endif } @@ -1237,7 +1201,7 @@ bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumu return false; bool isControlClip = hasControlClip(); - bool isOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer(); + bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer(); if (!isControlClip && !isOverflowClip) return false; @@ -1259,7 +1223,7 @@ bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumu void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, const LayoutPoint& accumulatedOffset) { - ASSERT(hasControlClip() || (hasOverflowClip() && !hasSelfPaintingLayer())); + ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer())); paintInfo.context->restore(); if (originalPhase == PaintPhaseOutline) { @@ -1292,9 +1256,10 @@ LayoutRect RenderBox::clipRect(const LayoutPoint& location, RenderRegion* region { LayoutRect borderBoxRect = borderBoxRectInRegion(region); LayoutRect clipRect = LayoutRect(borderBoxRect.location() + location, borderBoxRect.size()); + RenderView* renderView = view(); if (!style()->clipLeft().isAuto()) { - LayoutUnit c = style()->clipLeft().calcValue(borderBoxRect.width()); + LayoutUnit c = valueForLength(style()->clipLeft(), borderBoxRect.width(), renderView); clipRect.move(c, 0); clipRect.contract(c, 0); } @@ -1303,16 +1268,16 @@ LayoutRect RenderBox::clipRect(const LayoutPoint& location, RenderRegion* region // from the left and top edges. Therefore it's better to avoid constraining to smaller widths and heights. if (!style()->clipRight().isAuto()) - clipRect.contract(width() - style()->clipRight().calcValue(width()), 0); + clipRect.contract(width() - valueForLength(style()->clipRight(), width(), renderView), 0); if (!style()->clipTop().isAuto()) { - LayoutUnit c = style()->clipTop().calcValue(borderBoxRect.height()); + LayoutUnit c = valueForLength(style()->clipTop(), borderBoxRect.height(), renderView); clipRect.move(0, c); clipRect.contract(0, c); } if (!style()->clipBottom().isAuto()) - clipRect.contract(0, height() - style()->clipBottom().calcValue(height())); + clipRect.contract(0, height() - valueForLength(style()->clipBottom(), height(), renderView)); return clipRect; } @@ -1323,7 +1288,7 @@ LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStar LayoutUnit logicalTopPosition = logicalTop(); LayoutUnit adjustedPageOffsetForContainingBlock = offsetFromLogicalTopOfFirstPage - logicalTop(); if (region) { - LayoutUnit offsetFromLogicalTopOfRegion = region ? region->offsetFromLogicalTopOfFirstPage() - offsetFromLogicalTopOfFirstPage : zeroLayoutUnit; + LayoutUnit offsetFromLogicalTopOfRegion = region ? region->offsetFromLogicalTopOfFirstPage() - offsetFromLogicalTopOfFirstPage : ZERO_LAYOUT_UNIT; logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion); containingBlockRegion = cb->clampToStartAndEndRegions(region); } @@ -1378,6 +1343,20 @@ LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion return max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth())); } +LayoutUnit RenderBox::containingBlockAvailableLineWidthInRegion(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const +{ + RenderBlock* cb = containingBlock(); + RenderRegion* containingBlockRegion = 0; + LayoutUnit logicalTopPosition = logicalTop(); + LayoutUnit adjustedPageOffsetForContainingBlock = offsetFromLogicalTopOfFirstPage - logicalTop(); + if (region) { + LayoutUnit offsetFromLogicalTopOfRegion = region ? region->offsetFromLogicalTopOfFirstPage() - offsetFromLogicalTopOfFirstPage : ZERO_LAYOUT_UNIT; + logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion); + containingBlockRegion = cb->clampToStartAndEndRegions(region); + } + return cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock); +} + LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const { RenderBlock* cb = containingBlock(); @@ -1396,7 +1375,7 @@ LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const return cb->computeContentBoxLogicalHeight(logicalHeightLength.value()); } -void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, bool* wasFixed) const +void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, ApplyContainerFlipOrNot, bool* wasFixed) const { if (repaintContainer == this) return; @@ -1450,11 +1429,11 @@ void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool // Transform from render flow coordinates into region coordinates. RenderRegion* region = toRenderFlowThread(o)->mapFromFlowToRegion(transformState); if (region) - region->mapLocalToContainer(region->containerForRepaint(), fixed, useTransforms, transformState, wasFixed); + region->mapLocalToContainer(region->containerForRepaint(), fixed, useTransforms, transformState, DoNotApplyContainerFlip, wasFixed); return; } - o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, wasFixed); + o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, DoNotApplyContainerFlip, wasFixed); } void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const @@ -1533,7 +1512,7 @@ void RenderBox::positionLineBox(InlineBox* box) RootInlineBox* root = box->root(); root->block()->setStaticInlinePositionForChild(this, root->lineTopWithLeading(), roundedLayoutUnit(box->logicalLeft())); if (style()->hasStaticInlinePosition(box->isHorizontal())) - setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly. + setChildNeedsLayout(true, MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly. } else { // Our object was a block originally, so we make our normal flow position be // just below the line box (as though all the inlines that came before us got @@ -1541,7 +1520,7 @@ void RenderBox::positionLineBox(InlineBox* box) // in flow). This value was cached in the y() of the box. layer()->setStaticBlockPosition(box->logicalTop()); if (style()->hasStaticBlockPosition(box->isHorizontal())) - setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly. + setChildNeedsLayout(true, MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly. } // Nuke the box. @@ -1641,18 +1620,6 @@ void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, La if (isWritingModeRoot() && !isPositioned()) flipForWritingMode(rect); -#if ENABLE(CSS_FILTERS) - if (styleToUse->hasFilterOutsets()) { - LayoutUnit topOutset; - LayoutUnit rightOutset; - LayoutUnit bottomOutset; - LayoutUnit leftOutset; - styleToUse->filter().getOutsets(topOutset, rightOutset, bottomOutset, leftOutset); - rect.move(-leftOutset, -topOutset); - rect.expand(leftOutset + rightOutset, topOutset + bottomOutset); - } -#endif - LayoutPoint topLeft = rect.location(); topLeft.move(locationOffset()); @@ -1779,10 +1746,11 @@ void RenderBox::computeLogicalWidthInRegion(RenderRegion* region, LayoutUnit off if (isInline() && !isInlineBlockOrInlineTable()) { // just calculate margins - setMarginStart(styleToUse->marginStart().calcMinValue(containerLogicalWidth)); - setMarginEnd(styleToUse->marginEnd().calcMinValue(containerLogicalWidth)); + RenderView* renderView = view(); + setMarginStart(minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView)); + setMarginEnd(minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView)); if (treatAsReplaced) - setLogicalWidth(max<LayoutUnit>(logicalWidthLength.calcFloatValue(0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth())); + setLogicalWidth(max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth())); return; } @@ -1817,12 +1785,17 @@ void RenderBox::computeLogicalWidthInRegion(RenderRegion* region, LayoutUnit off } // Margin calculations. - if (logicalWidthLength.isAuto() || hasPerpendicularContainingBlock) { - setMarginStart(styleToUse->marginStart().calcMinValue(containerLogicalWidth)); - setMarginEnd(styleToUse->marginEnd().calcMinValue(containerLogicalWidth)); - } else - computeInlineDirectionMargins(cb, containerLogicalWidth, logicalWidth()); - + if (hasPerpendicularContainingBlock || isFloating() || isInline()) { + RenderView* renderView = view(); + setMarginStart(minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView)); + setMarginEnd(minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView)); + } else { + LayoutUnit containerLogicalWidthForAutoMargins = containerLogicalWidth; + if (avoidsFloats() && cb->containsFloats()) + containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region, offsetFromLogicalTopOfFirstPage); + computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth()); + } + if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (logicalWidth() + marginStart() + marginEnd()) && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated()) cb->setMarginEndForChild(this, containerLogicalWidth - logicalWidth() - cb->marginStartForChild(this)); @@ -1841,9 +1814,12 @@ LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(LogicalWidthType widthTyp else logicalWidth = styleToUse->logicalMaxWidth(); + ASSERT(!logicalWidth.isUndefined()); + if (logicalWidth.isIntrinsicOrAuto()) { - LayoutUnit marginStart = styleToUse->marginStart().calcMinValue(availableLogicalWidth); - LayoutUnit marginEnd = styleToUse->marginEnd().calcMinValue(availableLogicalWidth); + RenderView* renderView = view(); + LayoutUnit marginStart = minimumValueForLength(styleToUse->marginStart(), availableLogicalWidth, renderView); + LayoutUnit marginEnd = minimumValueForLength(styleToUse->marginEnd(), availableLogicalWidth, renderView); logicalWidthResult = availableLogicalWidth - marginStart - marginEnd; if (shrinkToAvoidFloats() && cb->containsFloats()) @@ -1854,7 +1830,7 @@ LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(LogicalWidthType widthTyp logicalWidthResult = min(logicalWidthResult, maxPreferredLogicalWidth()); } } else // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead. - logicalWidthResult = computeBorderBoxLogicalWidth(logicalWidth.calcValue(availableLogicalWidth)); + logicalWidthResult = computeBorderBoxLogicalWidth(valueForLength(logicalWidth, availableLogicalWidth, view())); return logicalWidthResult; } @@ -1922,11 +1898,12 @@ void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, Layo const RenderStyle* containingBlockStyle = containingBlock->style(); Length marginStartLength = style()->marginStartUsing(containingBlockStyle); Length marginEndLength = style()->marginEndUsing(containingBlockStyle); + RenderView* renderView = view(); if (isFloating() || isInline()) { // Inline blocks/tables and floats don't have their margins increased. - containingBlock->setMarginStartForChild(this, marginStartLength.calcMinValue(containerWidth)); - containingBlock->setMarginEndForChild(this, marginEndLength.calcMinValue(containerWidth)); + containingBlock->setMarginStartForChild(this, minimumValueForLength(marginStartLength, containerWidth, renderView)); + containingBlock->setMarginEndForChild(this, minimumValueForLength(marginEndLength, containerWidth, renderView)); return; } @@ -1940,7 +1917,7 @@ void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, Layo // Case Two: The object is being pushed to the start of the containing block's available logical width. if (marginEndLength.isAuto() && childWidth < containerWidth) { - containingBlock->setMarginStartForChild(this, marginStartLength.calcValue(containerWidth)); + containingBlock->setMarginStartForChild(this, valueForLength(marginStartLength, containerWidth, renderView)); containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this)); return; } @@ -1949,15 +1926,15 @@ void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, Layo bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT) || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT)); if ((marginStartLength.isAuto() && childWidth < containerWidth) || pushToEndFromTextAlign) { - containingBlock->setMarginEndForChild(this, marginEndLength.calcValue(containerWidth)); + containingBlock->setMarginEndForChild(this, valueForLength(marginEndLength, containerWidth, renderView)); containingBlock->setMarginStartForChild(this, containerWidth - childWidth - containingBlock->marginEndForChild(this)); return; } // Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3). In that case // auto margins will just turn into 0. - containingBlock->setMarginStartForChild(this, marginStartLength.calcMinValue(containerWidth)); - containingBlock->setMarginEndForChild(this, marginEndLength.calcMinValue(containerWidth)); + containingBlock->setMarginStartForChild(this, minimumValueForLength(marginStartLength, containerWidth, renderView)); + containingBlock->setMarginEndForChild(this, minimumValueForLength(marginEndLength, containerWidth, renderView)); } RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage, RenderBoxRegionInfoFlags cacheFlag) const @@ -2022,8 +1999,7 @@ RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, Layout LayoutUnit logicalLeftOffset = 0; if (!isPositioned() && avoidsFloats() && cb->containsFloats()) { - LayoutUnit startPositionDelta = cb->computeStartPositionDeltaForChildAvoidingFloats(this, marginStartInRegion, logicalWidthInRegion, - region, offsetFromLogicalTopOfFirstPage); + LayoutUnit startPositionDelta = cb->computeStartPositionDeltaForChildAvoidingFloats(this, marginStartInRegion, region, offsetFromLogicalTopOfFirstPage); if (cb->style()->isLeftToRightDirection()) logicalLeftDelta += startPositionDelta; else @@ -2152,18 +2128,24 @@ void RenderBox::computeLogicalHeight() } } -LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& h) +LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& height) +{ + LayoutUnit logicalHeight = computeContentLogicalHeightUsing(height); + if (logicalHeight != -1) + logicalHeight = computeBorderBoxLogicalHeight(logicalHeight); + return logicalHeight; +} + +LayoutUnit RenderBox::computeContentLogicalHeightUsing(const Length& height) { LayoutUnit logicalHeight = -1; - if (!h.isAuto()) { - if (h.isFixed()) - logicalHeight = h.value(); - else if (h.isPercent()) - logicalHeight = computePercentageLogicalHeight(h); - if (logicalHeight != -1) { - logicalHeight = computeBorderBoxLogicalHeight(logicalHeight); - return logicalHeight; - } + if (!height.isAuto()) { + if (height.isFixed()) + logicalHeight = height.value(); + else if (height.isPercent()) + logicalHeight = computePercentageLogicalHeight(height); + else if (height.isViewportPercentage()) + logicalHeight = valueForLength(height, 0, view()); } return logicalHeight; } @@ -2241,7 +2223,7 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) result = cb->computeContentBoxLogicalHeight(cb->availableLogicalHeight()); if (result != -1) { - result = height.calcValue(result); + result = valueForLength(height, result); if (includeBorderPadding) { // It is necessary to use the border-box to match WinIE's broken // box model. This is essential for sizing inside @@ -2270,13 +2252,18 @@ LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) cons switch (logicalWidth.type()) { case Fixed: return computeContentBoxLogicalWidth(logicalWidth.value()); - case Percent: { + case ViewportPercentageWidth: + case ViewportPercentageHeight: + case ViewportPercentageMin: + return computeContentBoxLogicalWidth(valueForLength(logicalWidth, 0, view())); + case Percent: + case Calculated: { // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the // containing block's block-flow. // https://bugs.webkit.org/show_bug.cgi?id=46496 const LayoutUnit cw = isPositioned() ? containingBlockLogicalWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent(); if (cw > 0) - return computeContentBoxLogicalWidth(logicalWidth.calcMinValue(cw)); + return computeContentBoxLogicalWidth(minimumValueForLength(logicalWidth, cw)); } // fall through default: @@ -2302,6 +2289,7 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) co case Fixed: return computeContentBoxLogicalHeight(logicalHeight.value()); case Percent: + case Calculated: { RenderObject* cb = isPositioned() ? container() : containingBlock(); while (cb->isAnonymous()) { @@ -2318,7 +2306,7 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) co block->computeLogicalHeight(); LayoutUnit newHeight = block->computeContentBoxLogicalHeight(block->contentHeight()); block->setHeight(oldHeight); - return computeContentBoxLogicalHeight(logicalHeight.calcValue(newHeight)); + return computeContentBoxLogicalHeight(valueForLength(logicalHeight, newHeight)); } // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the @@ -2339,13 +2327,18 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) co // Don't let table cells squeeze percent-height replaced elements // <http://bugs.webkit.org/show_bug.cgi?id=15359> availableHeight = max(availableHeight, intrinsicLogicalHeight()); - return logicalHeight.calcValue(availableHeight - borderAndPaddingLogicalHeight()); + return valueForLength(logicalHeight, availableHeight - borderAndPaddingLogicalHeight()); } cb = cb->containingBlock(); + toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this)); } } - return computeContentBoxLogicalHeight(logicalHeight.calcValue(availableHeight)); + return computeContentBoxLogicalHeight(valueForLength(logicalHeight, availableHeight)); } + case ViewportPercentageWidth: + case ViewportPercentageHeight: + case ViewportPercentageMin: + return computeContentBoxLogicalHeight(valueForLength(logicalHeight, 0, view())); default: return intrinsicLogicalHeight(); } @@ -2379,7 +2372,7 @@ LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h) const availableHeight = containingBlockLogicalHeightForPositioned(containingBlock()); else availableHeight = containingBlock()->availableLogicalHeight(); - return computeContentBoxLogicalHeight(h.calcValue(availableHeight)); + return computeContentBoxLogicalHeight(valueForLength(h, availableHeight)); } // FIXME: We can't just check top/bottom here. @@ -2409,10 +2402,10 @@ void RenderBox::computeBlockDirectionMargins(RenderBlock* containingBlock) // Margins are calculated with respect to the logical width of // the containing block (8.3) LayoutUnit cw = containingBlockLogicalWidthForContent(); - + RenderView* renderView = view(); RenderStyle* containingBlockStyle = containingBlock->style(); - containingBlock->setMarginBeforeForChild(this, style()->marginBeforeUsing(containingBlockStyle).calcMinValue(cw)); - containingBlock->setMarginAfterForChild(this, style()->marginAfterUsing(containingBlockStyle).calcMinValue(cw)); + containingBlock->setMarginBeforeForChild(this, minimumValueForLength(style()->marginBeforeUsing(containingBlockStyle), cw, renderView)); + containingBlock->setMarginAfterForChild(this, minimumValueForLength(style()->marginAfterUsing(containingBlockStyle), cw, renderView)); } LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* region, @@ -2735,6 +2728,7 @@ void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const Re bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto(); bool logicalLeftIsAuto = logicalLeft.isAuto(); bool logicalRightIsAuto = logicalRight.isAuto(); + RenderView* renderView = view(); if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) { /*-----------------------------------------------------------------------*\ @@ -2752,10 +2746,10 @@ void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const Re // NOTE: It is not necessary to solve for 'right' in the over constrained // case because the value is not used for any further calculations. - logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); - logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth)); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); + logicalWidthValue = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView)); - const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + logicalWidthValue + logicalRight.calcValue(containerLogicalWidth) + bordersPlusPadding); + const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + logicalWidthValue + valueForLength(logicalRight, containerLogicalWidth, renderView) + bordersPlusPadding); // Margins are now the only unknown if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) { @@ -2776,16 +2770,16 @@ void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const Re } } else if (marginLogicalLeft.isAuto()) { // Solve for left margin - marginLogicalRightValue = marginLogicalRight.calcValue(containerLogicalWidth); + marginLogicalRightValue = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); marginLogicalLeftValue = availableSpace - marginLogicalRightValue; } else if (marginLogicalRight.isAuto()) { // Solve for right margin - marginLogicalLeftValue = marginLogicalLeft.calcValue(containerLogicalWidth); + marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); marginLogicalRightValue = availableSpace - marginLogicalLeftValue; } else { // Over-constrained, solve for left if direction is RTL - marginLogicalLeftValue = marginLogicalLeft.calcValue(containerLogicalWidth); - marginLogicalRightValue = marginLogicalRight.calcValue(containerLogicalWidth); + marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); + marginLogicalRightValue = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); // Use the containing block's direction rather than the parent block's // per CSS 2.1 reference test abspos-non-replaced-width-margin-000. @@ -2835,8 +2829,8 @@ void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const Re // because the value is not used for any further calculations. // Calculate margins, 'auto' margins are ignored. - marginLogicalLeftValue = marginLogicalLeft.calcMinValue(containerLogicalWidth); - marginLogicalRightValue = marginLogicalRight.calcMinValue(containerLogicalWidth); + marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerLogicalWidth, renderView); + marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerLogicalWidth, renderView); const LayoutUnit availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding); @@ -2844,7 +2838,7 @@ void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const Re // Use rule/case that applies. if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) { // RULE 1: (use shrink-to-fit for width, and solve of left) - LayoutUnit logicalRightValue = logicalRight.calcValue(containerLogicalWidth); + LayoutUnit logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); // FIXME: would it be better to have shrink-to-fit in one step? LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding; @@ -2854,7 +2848,7 @@ void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const Re logicalLeftValue = availableSpace - (logicalWidthValue + logicalRightValue); } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) { // RULE 3: (use shrink-to-fit for width, and no need solve of right) - logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); // FIXME: would it be better to have shrink-to-fit in one step? LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding; @@ -2863,16 +2857,16 @@ void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const Re logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth); } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) { // RULE 4: (solve for left) - logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth)); - logicalLeftValue = availableSpace - (logicalWidthValue + logicalRight.calcValue(containerLogicalWidth)); + logicalWidthValue = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView)); + logicalLeftValue = availableSpace - (logicalWidthValue + valueForLength(logicalRight, containerLogicalWidth, renderView)); } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) { // RULE 5: (solve for width) - logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); - logicalWidthValue = availableSpace - (logicalLeftValue + logicalRight.calcValue(containerLogicalWidth)); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); + logicalWidthValue = availableSpace - (logicalLeftValue + valueForLength(logicalRight, containerLogicalWidth, renderView)); } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) { // RULE 6: (no need solve for right) - logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); - logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth)); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); + logicalWidthValue = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView)); } } @@ -3068,6 +3062,7 @@ void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, bool logicalHeightIsAuto = logicalHeightLength.isAuto(); bool logicalTopIsAuto = logicalTop.isAuto(); bool logicalBottomIsAuto = logicalBottom.isAuto(); + RenderView* renderView = view(); // Height is never unsolved for tables. if (isTable()) { @@ -3087,10 +3082,10 @@ void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, // NOTE: It is not necessary to solve for 'bottom' in the over constrained // case because the value is not used for any further calculations. - logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight)); - logicalTopValue = logicalTop.calcValue(containerLogicalHeight); + logicalHeightValue = computeContentBoxLogicalHeight(valueForLength(logicalHeightLength, containerLogicalHeight, renderView)); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); - const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight) + bordersPlusPadding); + const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView) + bordersPlusPadding); // Margins are now the only unknown if (marginBefore.isAuto() && marginAfter.isAuto()) { @@ -3100,16 +3095,16 @@ void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, marginAfterValue = availableSpace - marginBeforeValue; // account for odd valued differences } else if (marginBefore.isAuto()) { // Solve for top margin - marginAfterValue = marginAfter.calcValue(containerLogicalHeight); + marginAfterValue = valueForLength(marginAfter, containerLogicalHeight, renderView); marginBeforeValue = availableSpace - marginAfterValue; } else if (marginAfter.isAuto()) { // Solve for bottom margin - marginBeforeValue = marginBefore.calcValue(containerLogicalHeight); + marginBeforeValue = valueForLength(marginBefore, containerLogicalHeight, renderView); marginAfterValue = availableSpace - marginBeforeValue; } else { // Over-constrained, (no need solve for bottom) - marginBeforeValue = marginBefore.calcValue(containerLogicalHeight); - marginAfterValue = marginAfter.calcValue(containerLogicalHeight); + marginBeforeValue = valueForLength(marginBefore, containerLogicalHeight, renderView); + marginAfterValue = valueForLength(marginAfter, containerLogicalHeight, renderView); } } else { /*--------------------------------------------------------------------*\ @@ -3138,8 +3133,8 @@ void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, // because the value is not used for any further calculations. // Calculate margins, 'auto' margins are ignored. - marginBeforeValue = marginBefore.calcMinValue(containerLogicalHeight); - marginAfterValue = marginAfter.calcMinValue(containerLogicalHeight); + marginBeforeValue = minimumValueForLength(marginBefore, containerLogicalHeight, renderView); + marginAfterValue = minimumValueForLength(marginAfter, containerLogicalHeight, renderView); const LayoutUnit availableSpace = containerLogicalHeight - (marginBeforeValue + marginAfterValue + bordersPlusPadding); @@ -3147,23 +3142,23 @@ void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) { // RULE 1: (height is content based, solve of top) logicalHeightValue = contentLogicalHeight; - logicalTopValue = availableSpace - (logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight)); + logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView)); } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) { // RULE 3: (height is content based, no need solve of bottom) - logicalTopValue = logicalTop.calcValue(containerLogicalHeight); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); logicalHeightValue = contentLogicalHeight; } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) { // RULE 4: (solve of top) - logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight)); - logicalTopValue = availableSpace - (logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight)); + logicalHeightValue = computeContentBoxLogicalHeight(valueForLength(logicalHeightLength, containerLogicalHeight, renderView)); + logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView)); } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) { // RULE 5: (solve of height) - logicalTopValue = logicalTop.calcValue(containerLogicalHeight); - logicalHeightValue = max<LayoutUnit>(0, availableSpace - (logicalTopValue + logicalBottom.calcValue(containerLogicalHeight))); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); + logicalHeightValue = max<LayoutUnit>(0, availableSpace - (logicalTopValue + valueForLength(logicalBottom, containerLogicalHeight, renderView))); } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) { // RULE 6: (no need solve of bottom) - logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight)); - logicalTopValue = logicalTop.calcValue(containerLogicalHeight); + logicalHeightValue = computeContentBoxLogicalHeight(valueForLength(logicalHeightLength, containerLogicalHeight, renderView)); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); } } @@ -3239,13 +3234,14 @@ void RenderBox::computePositionedLogicalWidthReplaced() \*-----------------------------------------------------------------------*/ LayoutUnit logicalLeftValue = 0; LayoutUnit logicalRightValue = 0; + RenderView* renderView = view(); if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) { // 'left' and 'right' cannot be 'auto' due to step 3 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto())); - logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); - logicalRightValue = logicalRight.calcValue(containerLogicalWidth); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); + logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); LayoutUnit difference = availableSpace - (logicalLeftValue + logicalRightValue); if (difference > 0) { @@ -3268,39 +3264,39 @@ void RenderBox::computePositionedLogicalWidthReplaced() * that value. \*-----------------------------------------------------------------------*/ } else if (logicalLeft.isAuto()) { - marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth); - marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth); - logicalRightValue = logicalRight.calcValue(containerLogicalWidth); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); + logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); // Solve for 'left' logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias); } else if (logicalRight.isAuto()) { - marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth); - marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth); - logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); // Solve for 'right' logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias); } else if (marginLogicalLeft.isAuto()) { - marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth); - logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); - logicalRightValue = logicalRight.calcValue(containerLogicalWidth); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); + logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); // Solve for 'margin-left' marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias); } else if (marginLogicalRight.isAuto()) { - marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth); - logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); - logicalRightValue = logicalRight.calcValue(containerLogicalWidth); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); + logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); // Solve for 'margin-right' marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias); } else { // Nothing is 'auto', just calculate the values. - marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth); - marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth); - logicalRightValue = logicalRight.calcValue(containerLogicalWidth); - logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); + logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); + logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); // If the containing block is right-to-left, then push the left position as far to the right as possible if (containerDirection == RTL) { int totalLogicalWidth = logicalWidth() + logicalLeftValue + logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias; @@ -3363,6 +3359,7 @@ void RenderBox::computePositionedLogicalHeightReplaced() Length logicalTop = style()->logicalTop(); Length logicalBottom = style()->logicalBottom(); + RenderView* renderView = view(); /*-----------------------------------------------------------------------*\ * 1. The used value of 'height' is determined as for inline replaced @@ -3406,8 +3403,8 @@ void RenderBox::computePositionedLogicalHeightReplaced() // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined. ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto())); - logicalTopValue = logicalTop.calcValue(containerLogicalHeight); - logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); + logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView); LayoutUnit difference = availableSpace - (logicalTopValue + logicalBottomValue); // NOTE: This may result in negative values. @@ -3419,39 +3416,39 @@ void RenderBox::computePositionedLogicalHeightReplaced() * for that value. \*-----------------------------------------------------------------------*/ } else if (logicalTop.isAuto()) { - marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight); - marginAfterAlias = marginAfter.calcValue(containerLogicalHeight); - logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight); + marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView); + marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView); + logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView); // Solve for 'top' logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias); } else if (logicalBottom.isAuto()) { - marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight); - marginAfterAlias = marginAfter.calcValue(containerLogicalHeight); - logicalTopValue = logicalTop.calcValue(containerLogicalHeight); + marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView); + marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); // Solve for 'bottom' // NOTE: It is not necessary to solve for 'bottom' because we don't ever // use the value. } else if (marginBefore.isAuto()) { - marginAfterAlias = marginAfter.calcValue(containerLogicalHeight); - logicalTopValue = logicalTop.calcValue(containerLogicalHeight); - logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight); + marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); + logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView); // Solve for 'margin-top' marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias); } else if (marginAfter.isAuto()) { - marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight); - logicalTopValue = logicalTop.calcValue(containerLogicalHeight); - logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight); + marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); + logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView); // Solve for 'margin-bottom' marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias); } else { // Nothing is 'auto', just calculate the values. - marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight); - marginAfterAlias = marginAfter.calcValue(containerLogicalHeight); - logicalTopValue = logicalTop.calcValue(containerLogicalHeight); + marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView); + marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView); + logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); // NOTE: It is not necessary to solve for 'bottom' because we don't ever // use the value. } @@ -3529,7 +3526,7 @@ VisiblePosition RenderBox::positionForPoint(const LayoutPoint& point) } // Pass off to the closest child. - LayoutUnit minDist = numeric_limits<LayoutUnit>::max(); + LayoutUnit minDist = MAX_LAYOUT_UNIT; RenderBox* closestRenderer = 0; LayoutPoint adjustedPoint = point; if (isTableRow()) @@ -3545,9 +3542,9 @@ VisiblePosition RenderBox::positionForPoint(const LayoutPoint& point) RenderBox* renderer = toRenderBox(renderObject); - LayoutUnit top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? zeroLayoutUnit : renderer->y()); + LayoutUnit top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? ZERO_LAYOUT_UNIT : renderer->y()); LayoutUnit bottom = top + renderer->contentHeight(); - LayoutUnit left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? zeroLayoutUnit : renderer->x()); + LayoutUnit left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? ZERO_LAYOUT_UNIT : renderer->x()); LayoutUnit right = left + renderer->contentWidth(); if (point.x() <= right && point.x() >= left && point.y() <= top && point.y() >= bottom) { @@ -3600,9 +3597,9 @@ bool RenderBox::shrinkToAvoidFloats() const // Floating objects don't shrink. Objects that don't avoid floats don't shrink. Marquees don't shrink. if ((isInline() && !isHTMLMarquee()) || !avoidsFloats() || isFloating()) return false; - - // All auto-width objects that avoid floats should always use lineWidth. - return style()->width().isAuto(); + + // Only auto width objects can possibly shrink to avoid floats. + return style()->width().isAuto(); } bool RenderBox::avoidsFloats() const @@ -3612,7 +3609,7 @@ bool RenderBox::avoidsFloats() const void RenderBox::addVisualEffectOverflow() { - if (!style()->boxShadow() && !style()->hasBorderImageOutsets() && !style()->hasFilterOutsets()) + if (!style()->boxShadow() && !style()->hasBorderImageOutsets()) return; bool isFlipped = style()->isFlippedBlocksWritingMode(); @@ -3655,21 +3652,6 @@ void RenderBox::addVisualEffectOverflow() overflowMaxY = max(overflowMaxY, borderBox.maxY() + ((!isFlipped || !isHorizontal) ? borderOutsetBottom : borderOutsetTop)); } -#if ENABLE(CSS_FILTERS) - // Compute any filter outset overflow. - if (style()->hasFilterOutsets()) { - LayoutUnit filterOutsetLeft; - LayoutUnit filterOutsetRight; - LayoutUnit filterOutsetTop; - LayoutUnit filterOutsetBottom; - style()->getFilterOutsets(filterOutsetTop, filterOutsetRight, filterOutsetBottom, filterOutsetLeft); - - overflowMinX = min(overflowMinX, borderBox.x() - filterOutsetLeft); - overflowMaxX = max(overflowMaxX, borderBox.maxX() + filterOutsetRight); - overflowMinY = min(overflowMinY, borderBox.y() - filterOutsetTop); - overflowMaxY = max(overflowMaxY, borderBox.maxY() + filterOutsetBottom); - } -#endif // Add in the final overflow with shadows and outsets combined. addVisualOverflow(LayoutRect(overflowMinX, overflowMinY, overflowMaxX - overflowMinX, overflowMaxY - overflowMinY)); } @@ -3733,10 +3715,6 @@ void RenderBox::addLayoutOverflow(const LayoutRect& rect) if (!m_overflow) m_overflow = adoptPtr(new RenderOverflow(clientBox, borderBoxRect())); - // Lazily allocate our layer as we will need it to hold our scroll information. - if (hasOverflowClip()) - ensureLayer(); - m_overflow->addLayoutOverflow(overflowRect); } @@ -4029,4 +4007,78 @@ bool RenderBox::hasRelativeDimensions() const || style()->minHeight().isPercent() || style()->minWidth().isPercent(); } +bool RenderBox::hasRelativeLogicalHeight() const +{ + return style()->logicalHeight().isPercent() + || style()->logicalMinHeight().isPercent() + || style()->logicalMaxHeight().isPercent(); +} + +void RenderBox::moveChildTo(RenderBox* toBox, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert) +{ + ASSERT(this == child->parent()); + ASSERT(!beforeChild || toBox == beforeChild->parent()); + if (fullRemoveInsert && toBox->isRenderBlock()) { + // Takes care of adding the new child correctly if toBlock and fromBlock + // have different kind of children (block vs inline). + toBox->addChild(virtualChildren()->removeChildNode(this, child), beforeChild); + } else + toBox->virtualChildren()->insertChildNode(toBox, virtualChildren()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert); +} + +void RenderBox::moveChildrenTo(RenderBox* toBox, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert) +{ + ASSERT(!beforeChild || toBox == beforeChild->parent()); + for (RenderObject* child = startChild; child && child != endChild; ) { + // Save our next sibling as moveChildTo will clear it. + RenderObject* nextSibling = child->nextSibling(); + moveChildTo(toBox, child, beforeChild, fullRemoveInsert); + child = nextSibling; + } +} + +static void markBoxForRelayoutAfterSplit(RenderBox* box) +{ + // FIXME: The table code should handle that automatically. If not, + // we should fix it and remove the table part checks. + if (box->isTable()) + toRenderTable(box)->setNeedsSectionRecalc(); + else if (box->isTableSection()) + toRenderTableSection(box)->setNeedsCellRecalc(); + + box->setNeedsLayoutAndPrefWidthsRecalc(); +} + +RenderObject* RenderBox::splitAnonymousBoxesAroundChild(RenderObject* beforeChild) +{ + bool didSplitParentAnonymousBoxes = false; + + while (beforeChild->parent() != this) { + RenderBox* boxToSplit = toRenderBox(beforeChild->parent()); + if (boxToSplit->firstChild() != beforeChild && boxToSplit->isAnonymous()) { + didSplitParentAnonymousBoxes = true; + + // We have to split the parent box into two boxes and move children + // from |beforeChild| to end into the new post box. + RenderBox* postBox = boxToSplit->createAnonymousBoxWithSameTypeAs(this); + postBox->setChildrenInline(boxToSplit->childrenInline()); + RenderBox* parentBox = toRenderBox(boxToSplit->parent()); + parentBox->virtualChildren()->insertChildNode(parentBox, postBox, boxToSplit->nextSibling()); + boxToSplit->moveChildrenTo(postBox, beforeChild, 0, boxToSplit->hasLayer()); + + markBoxForRelayoutAfterSplit(boxToSplit); + markBoxForRelayoutAfterSplit(postBox); + + beforeChild = postBox; + } else + beforeChild = boxToSplit; + } + + if (didSplitParentAnonymousBoxes) + markBoxForRelayoutAfterSplit(this); + + ASSERT(beforeChild->parent() == this); + return beforeChild; +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h index 2bba71f0b..794ed39e2 100644 --- a/Source/WebCore/rendering/RenderBox.h +++ b/Source/WebCore/rendering/RenderBox.h @@ -42,10 +42,7 @@ public: RenderBox(Node*); virtual ~RenderBox(); - virtual bool requiresLayer() const OVERRIDE { return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || requiresLayerForOverflowClip() || hasTransform() || hasMask() || hasReflection() || hasFilter() || style()->specifiesColumns(); } - bool requiresLayerForOverflowClip() const; - - bool hasOverflowClipWithLayer() const { return hasOverflowClip() && hasLayer(); } + virtual bool requiresLayer() const OVERRIDE { return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasHiddenBackface() || hasMask() || hasReflection() || hasFilter() || style()->specifiesColumns(); } // Use this with caution! No type checking is done! RenderBox* firstChildBox() const; @@ -56,9 +53,8 @@ public: LayoutUnit width() const { return m_frameRect.width(); } LayoutUnit height() const { return m_frameRect.height(); } - // FIXME: The implementation for these functions will change once we move to subpixel layout. See bug 60318. - int pixelSnappedWidth() const { return m_frameRect.width(); } - int pixelSnappedHeight() const { return m_frameRect.height(); } + int pixelSnappedWidth() const { return m_frameRect.pixelSnappedWidth(); } + int pixelSnappedHeight() const { return m_frameRect.pixelSnappedHeight(); } // These represent your location relative to your container as a physical offset. // In layout related methods you almost always want the logical location (e.g. x() and y()). @@ -123,6 +119,7 @@ public: LayoutPoint location() const { return m_frameRect.location(); } LayoutSize locationOffset() const { return LayoutSize(x(), y()); } LayoutSize size() const { return m_frameRect.size(); } + IntSize pixelSnappedSize() const { return m_frameRect.pixelSnappedSize(); } void setLocation(const LayoutPoint& location) { m_frameRect.setLocation(location); } @@ -130,20 +127,24 @@ public: void move(LayoutUnit dx, LayoutUnit dy) { m_frameRect.move(dx, dy); } LayoutRect frameRect() const { return m_frameRect; } + IntRect pixelSnappedFrameRect() const { return pixelSnappedIntRect(m_frameRect); } void setFrameRect(const LayoutRect& rect) { m_frameRect = rect; } - // FIXME: We shouldn't be returning this as a LayoutRect, since it loses its position and won't properly pixel snap. LayoutRect borderBoxRect() const { return LayoutRect(LayoutPoint(), size()); } - IntRect pixelSnappedBorderBoxRect() const { return IntRect(IntPoint(), IntSize(m_frameRect.pixelSnappedWidth(), m_frameRect.pixelSnappedHeight())); } - virtual IntRect borderBoundingBox() const { return pixelSnappedBorderBoxRect(); } + IntRect pixelSnappedBorderBoxRect() const { return IntRect(IntPoint(), m_frameRect.pixelSnappedSize()); } + virtual IntRect borderBoundingBox() const { return pixelSnappedBorderBoxRect(); } - // The content area of the box (excludes padding and border). - LayoutRect contentBoxRect(PaddingOptions paddingOption = ExcludeIntrinsicPadding) const { return LayoutRect(borderLeft() + paddingLeft(paddingOption), borderTop() + paddingTop(paddingOption), contentWidth(paddingOption), contentHeight(paddingOption)); } + // The content area of the box (excludes padding - and intrinsic padding for table cells, etc... - and border). + LayoutRect contentBoxRect() const { return LayoutRect(borderLeft() + paddingLeft(), borderTop() + paddingTop(), contentWidth(), contentHeight()); } // The content box in absolute coords. Ignores transforms. - LayoutRect absoluteContentBox() const; + IntRect absoluteContentBox() const; // The content box converted to absolute coords (taking transforms into account). FloatQuad absoluteContentQuad() const; + // This returns the content area of the box (excluding padding and border). The only difference with contentBoxRect is that computedCSSContentBoxRect + // does include the intrinsic padding in the content box as this is what some callers expect (like getComputedStyle). + LayoutRect computedCSSContentBoxRect() const { return LayoutRect(borderLeft() + computedCSSPaddingLeft(), borderTop() + computedCSSPaddingTop(), clientWidth() - computedCSSPaddingLeft() - computedCSSPaddingRight(), clientHeight() - computedCSSPaddingTop() - computedCSSPaddingBottom()); } + // Bounds of the outline box in absolute coords. Respects transforms virtual LayoutRect outlineBoundsForRepaint(RenderBoxModelObject* /*repaintContainer*/, LayoutPoint* cachedOffsetToRepaintContainer) const; virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&); @@ -159,18 +160,18 @@ public: // but it is on the right in vertical-rl. LayoutRect layoutOverflowRect() const { return m_overflow ? m_overflow->layoutOverflowRect() : clientBoxRect(); } IntRect pixelSnappedLayoutOverflowRect() const { return pixelSnappedIntRect(layoutOverflowRect()); } - LayoutUnit minYLayoutOverflow() const { return m_overflow? m_overflow->minYLayoutOverflow() : borderTop(); } - LayoutUnit maxYLayoutOverflow() const { return m_overflow ? m_overflow->maxYLayoutOverflow() : borderTop() + clientHeight(); } - LayoutUnit minXLayoutOverflow() const { return m_overflow ? m_overflow->minXLayoutOverflow() : borderLeft(); } - LayoutUnit maxXLayoutOverflow() const { return m_overflow ? m_overflow->maxXLayoutOverflow() : borderLeft() + clientWidth(); } + LayoutUnit minYLayoutOverflow() const { return m_overflow? m_overflow->minYLayoutOverflow() : static_cast<LayoutUnit>(borderTop()); } + LayoutUnit maxYLayoutOverflow() const { return m_overflow ? m_overflow->maxYLayoutOverflow() : static_cast<LayoutUnit>(borderTop()) + clientHeight(); } + LayoutUnit minXLayoutOverflow() const { return m_overflow ? m_overflow->minXLayoutOverflow() : static_cast<LayoutUnit>(borderLeft()); } + LayoutUnit maxXLayoutOverflow() const { return m_overflow ? m_overflow->maxXLayoutOverflow() : static_cast<LayoutUnit>(borderLeft()) + clientWidth(); } LayoutSize maxLayoutOverflow() const { return LayoutSize(maxXLayoutOverflow(), maxYLayoutOverflow()); } LayoutUnit logicalLeftLayoutOverflow() const { return style()->isHorizontalWritingMode() ? minXLayoutOverflow() : minYLayoutOverflow(); } LayoutUnit logicalRightLayoutOverflow() const { return style()->isHorizontalWritingMode() ? maxXLayoutOverflow() : maxYLayoutOverflow(); } virtual LayoutRect visualOverflowRect() const { return m_overflow ? m_overflow->visualOverflowRect() : borderBoxRect(); } - LayoutUnit minYVisualOverflow() const { return m_overflow? m_overflow->minYVisualOverflow() : zeroLayoutUnit; } + LayoutUnit minYVisualOverflow() const { return m_overflow? m_overflow->minYVisualOverflow() : ZERO_LAYOUT_UNIT; } LayoutUnit maxYVisualOverflow() const { return m_overflow ? m_overflow->maxYVisualOverflow() : height(); } - LayoutUnit minXVisualOverflow() const { return m_overflow ? m_overflow->minXVisualOverflow() : zeroLayoutUnit; } + LayoutUnit minXVisualOverflow() const { return m_overflow ? m_overflow->minXVisualOverflow() : ZERO_LAYOUT_UNIT; } LayoutUnit maxXVisualOverflow() const { return m_overflow ? m_overflow->maxXVisualOverflow() : width(); } LayoutUnit logicalLeftVisualOverflow() const { return style()->isHorizontalWritingMode() ? minXVisualOverflow() : minYVisualOverflow(); } LayoutUnit logicalRightVisualOverflow() const { return style()->isHorizontalWritingMode() ? maxXVisualOverflow() : maxYVisualOverflow(); } @@ -185,10 +186,10 @@ public: void updateLayerTransform(); - LayoutUnit contentWidth(PaddingOptions paddingOption = ExcludeIntrinsicPadding) const { return clientWidth() - paddingLeft(paddingOption) - paddingRight(paddingOption); } - LayoutUnit contentHeight(PaddingOptions paddingOption = ExcludeIntrinsicPadding) const { return clientHeight() - paddingTop(paddingOption) - paddingBottom(paddingOption); } - LayoutUnit contentLogicalWidth(PaddingOptions paddingOption = ExcludeIntrinsicPadding) const { return style()->isHorizontalWritingMode() ? contentWidth(paddingOption) : contentHeight(paddingOption); } - LayoutUnit contentLogicalHeight(PaddingOptions paddingOption = ExcludeIntrinsicPadding) const { return style()->isHorizontalWritingMode() ? contentHeight(paddingOption) : contentWidth(paddingOption); } + LayoutUnit contentWidth() const { return clientWidth() - paddingLeft() - paddingRight(); } + LayoutUnit contentHeight() const { return clientHeight() - paddingTop() - paddingBottom(); } + LayoutUnit contentLogicalWidth() const { return style()->isHorizontalWritingMode() ? contentWidth() : contentHeight(); } + LayoutUnit contentLogicalHeight() const { return style()->isHorizontalWritingMode() ? contentHeight() : contentWidth(); } // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow) // to return the remaining width on a given line (and the height of a single line). @@ -315,13 +316,14 @@ public: virtual LayoutUnit containingBlockLogicalWidthForContent() const; LayoutUnit containingBlockLogicalWidthForContentInRegion(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const; + LayoutUnit containingBlockAvailableLineWidthInRegion(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const; LayoutUnit perpendicularContainingBlockLogicalHeight() const; virtual void computeLogicalWidth(); virtual void computeLogicalHeight(); RenderBoxRegionInfo* renderBoxRegionInfo(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage, RenderBoxRegionInfoFlags = CacheRenderBoxRegionInfo) const; - void computeLogicalWidthInRegion(RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = zeroLayoutUnit); + void computeLogicalWidthInRegion(RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = ZERO_LAYOUT_UNIT); bool stretchesToViewport() const { @@ -341,6 +343,7 @@ public: LayoutUnit computeLogicalWidthInRegionUsing(LogicalWidthType, LayoutUnit availableLogicalWidth, const RenderBlock* containingBlock, RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage); LayoutUnit computeLogicalHeightUsing(const Length& height); + LayoutUnit computeContentLogicalHeightUsing(const Length& height); LayoutUnit computeReplacedLogicalWidthUsing(Length width) const; LayoutUnit computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, bool includeMaxWidth = true) const; LayoutUnit computeReplacedLogicalHeightUsing(Length height) const; @@ -455,11 +458,10 @@ public: virtual void computeIntrinsicRatioInformation(FloatSize& /* intrinsicSize */, double& /* intrinsicRatio */, bool& /* isPercentageIntrinsicSize */) const { } IntSize scrolledContentOffset() const; - IntSize cachedSizeForOverflowClip() const; - void updateCachedSizeForOverflowClip(); - void clearCachedSizeForOverflowClip(); + LayoutSize cachedSizeForOverflowClip() const; virtual bool hasRelativeDimensions() const; + virtual bool hasRelativeLogicalHeight() const; bool hasHorizontalLayoutOverflow() const { @@ -483,6 +485,12 @@ public: return false; } + virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject*) const + { + ASSERT_NOT_REACHED(); + return 0; + } + protected: virtual void willBeDestroyed(); @@ -508,11 +516,37 @@ protected: virtual bool shouldComputeSizeAsReplaced() const { return isReplaced() && !isInlineBlockOrInlineTable(); } - virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&, bool* wasFixed = 0) const; + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const; void paintRootBoxFillLayers(const PaintInfo&); + // These functions are only used internally to manipulate the render tree structure via remove/insert/appendChildNode. + // Since they are typically called only to move objects around within anonymous blocks (which only have layers in + // the case of column spans), the default for fullRemoveInsert is false rather than true. + void moveChildTo(RenderBox* toBox, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert = false); + void moveChildTo(RenderBox* to, RenderObject* child, bool fullRemoveInsert = false) + { + moveChildTo(to, child, 0, fullRemoveInsert); + } + void moveAllChildrenTo(RenderBox* toBox, bool fullRemoveInsert = false) + { + moveAllChildrenTo(toBox, 0, fullRemoveInsert); + } + void moveAllChildrenTo(RenderBox* toBox, RenderObject* beforeChild, bool fullRemoveInsert = false) + { + moveChildrenTo(toBox, firstChild(), 0, beforeChild, fullRemoveInsert); + } + // Move all of the kids from |startChild| up to but excluding |endChild|. 0 can be passed as the |endChild| to denote + // that all the kids from |startChild| onwards should be moved. + void moveChildrenTo(RenderBox* toBox, RenderObject* startChild, RenderObject* endChild, bool fullRemoveInsert = false) + { + moveChildrenTo(toBox, startChild, endChild, 0, fullRemoveInsert); + } + void moveChildrenTo(RenderBox* toBox, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert = false); + + RenderObject* splitAnonymousBoxesAroundChild(RenderObject* beforeChild); + private: bool fixedElementLaysOutRelativeToFrame(Frame*, FrameView*) const; @@ -611,24 +645,6 @@ inline RenderBox* RenderBox::lastChildBox() const return toRenderBox(lastChild()); } -inline bool RenderBox::requiresLayerForOverflowClip() const -{ - if (!hasOverflowClip()) - return false; - - // The resizer is attached to the RenderLayer so we need one. - if (style()->resize() != RESIZE_NONE) - return true; - - // FIXME: overflow: auto could also lazily create its layer but some repainting - // issues are arising from that. - bool onlyOverflowHidden = style()->overflowX() == OHIDDEN && style()->overflowY() == OHIDDEN; - - // Currently {push|pop}ContentsClip do not handle properly all cases involving a clip - // with a border radius so we need a RenderLayer to handle them. - return !onlyOverflowHidden || style()->hasBorderRadius(); -} - } // namespace WebCore #endif // RenderBox_h diff --git a/Source/WebCore/rendering/RenderBoxModelObject.cpp b/Source/WebCore/rendering/RenderBoxModelObject.cpp index c709705bc..eed3577a3 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.cpp +++ b/Source/WebCore/rendering/RenderBoxModelObject.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "RenderBoxModelObject.h" +#include "FilterOperations.h" #include "GraphicsContext.h" #include "HTMLFrameOwnerElement.h" #include "HTMLNames.h" @@ -40,6 +41,11 @@ #include "TransformState.h" #include <wtf/CurrentTime.h> +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayerBacking.h" +#include "RenderLayerCompositor.h" +#endif + using namespace std; namespace WebCore { @@ -240,6 +246,70 @@ void RenderBoxModelObject::setSelectionState(SelectionState state) containingBlock->setSelectionState(state); } +#if USE(ACCELERATED_COMPOSITING) +void RenderBoxModelObject::contentChanged(ContentChangeType changeType) +{ + if (!hasLayer()) + return; + + layer()->contentChanged(changeType); +} + +bool RenderBoxModelObject::hasAcceleratedCompositing() const +{ + return view()->compositor()->hasAcceleratedCompositing(); +} + +bool RenderBoxModelObject::startTransition(double timeOffset, CSSPropertyID propertyId, const RenderStyle* fromStyle, const RenderStyle* toStyle) +{ + ASSERT(hasLayer()); + ASSERT(isComposited()); + return layer()->backing()->startTransition(timeOffset, propertyId, fromStyle, toStyle); +} + +void RenderBoxModelObject::transitionPaused(double timeOffset, CSSPropertyID propertyId) +{ + ASSERT(hasLayer()); + ASSERT(isComposited()); + layer()->backing()->transitionPaused(timeOffset, propertyId); +} + +void RenderBoxModelObject::transitionFinished(CSSPropertyID propertyId) +{ + ASSERT(hasLayer()); + ASSERT(isComposited()); + layer()->backing()->transitionFinished(propertyId); +} + +bool RenderBoxModelObject::startAnimation(double timeOffset, const Animation* animation, const KeyframeList& keyframes) +{ + ASSERT(hasLayer()); + ASSERT(isComposited()); + return layer()->backing()->startAnimation(timeOffset, animation, keyframes); +} + +void RenderBoxModelObject::animationPaused(double timeOffset, const String& name) +{ + ASSERT(hasLayer()); + ASSERT(isComposited()); + layer()->backing()->animationPaused(timeOffset, name); +} + +void RenderBoxModelObject::animationFinished(const String& name) +{ + ASSERT(hasLayer()); + ASSERT(isComposited()); + layer()->backing()->animationFinished(name); +} + +void RenderBoxModelObject::suspendAnimations(double time) +{ + ASSERT(hasLayer()); + ASSERT(isComposited()); + layer()->backing()->suspendAnimations(time); +} +#endif + bool RenderBoxModelObject::shouldPaintAtLowQuality(GraphicsContext* context, Image* image, const void* layer, const LayoutSize& size) { return imageQualityController()->shouldPaintAtLowQuality(context, this, image, layer, size); @@ -329,9 +399,13 @@ void RenderBoxModelObject::styleWillChange(StyleDifference diff, const RenderSty || !(oldStyle->clip() == newStyle->clip()) || oldStyle->hasClip() != newStyle->hasClip() || oldStyle->opacity() != newStyle->opacity() - || oldStyle->transform() != newStyle->transform()) + || oldStyle->transform() != newStyle->transform() +#if ENABLE(CSS_FILTERS) + || oldStyle->filter() != newStyle->filter() +#endif + ) layer()->repaintIncludingDescendants(); - } else if (newStyle->hasTransform() || newStyle->opacity() < 1) { + } else if (newStyle->hasTransform() || newStyle->opacity() < 1 || newStyle->hasFilter()) { // If we don't have a layer yet, but we are going to get one because of transform or opacity, // then we need to repaint the old position of the object. repaint(); @@ -351,28 +425,18 @@ void RenderBoxModelObject::styleWillChange(StyleDifference diff, const RenderSty RenderObject::styleWillChange(diff, newStyle); } -void RenderBoxModelObject::ensureLayer() -{ - if (m_layer) - return; - - m_layer = new (renderArena()) RenderLayer(this); - setHasLayer(true); - m_layer->insertOnlyThisLayer(); -} - void RenderBoxModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderObject::styleDidChange(diff, oldStyle); updateBoxModelInfoFromStyle(); - + if (requiresLayer()) { if (!layer() && layerCreationAllowedForSubtree()) { if (s_wasFloating && isFloating()) setChildNeedsLayout(true); - - ensureLayer(); - + m_layer = new (renderArena()) RenderLayer(this); + setHasLayer(true); + m_layer->insertOnlyThisLayer(); if (parent() && !needsLayout() && containingBlock()) { m_layer->setRepaintStatus(NeedsFullRepaint); // There is only one layer to update, it is not worth using |cachedOffset| since @@ -388,8 +452,6 @@ void RenderBoxModelObject::styleDidChange(StyleDifference diff, const RenderStyl setChildNeedsLayout(true); if (s_hadTransform) setNeedsLayoutAndPrefWidthsRecalc(); - if (hasOverflowClip()) - toRenderBox(this)->updateCachedSizeForOverflowClip(); } if (layer()) { @@ -437,12 +499,12 @@ LayoutUnit RenderBoxModelObject::relativePositionOffsetX() const if (!style()->left().isAuto()) { RenderBlock* cb = containingBlock(); if (!style()->right().isAuto() && !cb->style()->isLeftToRightDirection()) - return -style()->right().calcValue(cb->availableWidth()); - return offset + style()->left().calcValue(cb->availableWidth()); + return -valueForLength(style()->right(), cb->availableWidth(), view()); + return offset + valueForLength(style()->left(), cb->availableWidth(), view()); } if (!style()->right().isAuto()) { RenderBlock* cb = containingBlock(); - return offset + -style()->right().calcValue(cb->availableWidth()); + return offset + -valueForLength(style()->right(), cb->availableWidth(), view()); } return offset; } @@ -462,13 +524,13 @@ LayoutUnit RenderBoxModelObject::relativePositionOffsetY() const && (!containingBlock->style()->height().isAuto() || !style()->top().isPercent() || containingBlock->stretchesToViewport())) - return offset + style()->top().calcValue(containingBlock->availableHeight()); + return offset + valueForLength(style()->top(), containingBlock->availableHeight(), view()); if (!style()->bottom().isAuto() && (!containingBlock->style()->height().isAuto() || !style()->bottom().isPercent() || containingBlock->stretchesToViewport())) - return offset + -style()->bottom().calcValue(containingBlock->availableHeight()); + return offset + -valueForLength(style()->bottom(), containingBlock->availableHeight(), view()); return offset; } @@ -481,7 +543,7 @@ LayoutUnit RenderBoxModelObject::offsetLeft() const return 0; RenderBoxModelObject* offsetPar = offsetParent(); - LayoutUnit xPos = (isBox() ? toRenderBox(this)->left() : zeroLayoutUnit); + LayoutUnit xPos = (isBox() ? toRenderBox(this)->left() : ZERO_LAYOUT_UNIT); // If the offsetParent of the element is null, or is the HTML body element, // return the distance between the canvas origin and the left border edge @@ -515,7 +577,7 @@ LayoutUnit RenderBoxModelObject::offsetTop() const return 0; RenderBoxModelObject* offsetPar = offsetParent(); - LayoutUnit yPos = (isBox() ? toRenderBox(this)->top() : zeroLayoutUnit); + LayoutUnit yPos = (isBox() ? toRenderBox(this)->top() : ZERO_LAYOUT_UNIT); // If the offsetParent of the element is null, or is the HTML body element, // return the distance between the canvas origin and the top border edge @@ -542,92 +604,117 @@ LayoutUnit RenderBoxModelObject::offsetTop() const int RenderBoxModelObject::pixelSnappedOffsetWidth() const { - return offsetWidth(); + return snapSizeToPixel(offsetWidth(), offsetLeft()); } int RenderBoxModelObject::pixelSnappedOffsetHeight() const { - return offsetHeight(); + return snapSizeToPixel(offsetHeight(), offsetTop()); } -LayoutUnit RenderBoxModelObject::paddingTop(PaddingOptions) const +LayoutUnit RenderBoxModelObject::computedCSSPaddingTop() const { LayoutUnit w = 0; + RenderView* renderView = 0; Length padding = style()->paddingTop(); if (padding.isPercent()) w = containingBlock()->availableLogicalWidth(); - return padding.calcMinValue(w); + else if (padding.isViewportPercentage()) + renderView = view(); + return minimumValueForLength(padding, w, renderView); } -LayoutUnit RenderBoxModelObject::paddingBottom(PaddingOptions) const +LayoutUnit RenderBoxModelObject::computedCSSPaddingBottom() const { LayoutUnit w = 0; + RenderView* renderView = 0; Length padding = style()->paddingBottom(); if (padding.isPercent()) w = containingBlock()->availableLogicalWidth(); - return padding.calcMinValue(w); + else if (padding.isViewportPercentage()) + renderView = view(); + return minimumValueForLength(padding, w, renderView); } -LayoutUnit RenderBoxModelObject::paddingLeft(PaddingOptions) const +LayoutUnit RenderBoxModelObject::computedCSSPaddingLeft() const { LayoutUnit w = 0; + RenderView* renderView = 0; Length padding = style()->paddingLeft(); if (padding.isPercent()) w = containingBlock()->availableLogicalWidth(); - return padding.calcMinValue(w); + else if (padding.isViewportPercentage()) + renderView = view(); + return minimumValueForLength(padding, w, renderView); } -LayoutUnit RenderBoxModelObject::paddingRight(PaddingOptions) const +LayoutUnit RenderBoxModelObject::computedCSSPaddingRight() const { LayoutUnit w = 0; + RenderView* renderView = 0; Length padding = style()->paddingRight(); if (padding.isPercent()) w = containingBlock()->availableLogicalWidth(); - return padding.calcMinValue(w); + else if (padding.isViewportPercentage()) + renderView = view(); + return minimumValueForLength(padding, w, renderView); } -LayoutUnit RenderBoxModelObject::paddingBefore(PaddingOptions) const +LayoutUnit RenderBoxModelObject::computedCSSPaddingBefore() const { LayoutUnit w = 0; + RenderView* renderView = 0; Length padding = style()->paddingBefore(); if (padding.isPercent()) w = containingBlock()->availableLogicalWidth(); - return padding.calcMinValue(w); + else if (padding.isViewportPercentage()) + renderView = view(); + return minimumValueForLength(padding, w, renderView); } -LayoutUnit RenderBoxModelObject::paddingAfter(PaddingOptions) const +LayoutUnit RenderBoxModelObject::computedCSSPaddingAfter() const { LayoutUnit w = 0; + RenderView* renderView = 0; Length padding = style()->paddingAfter(); if (padding.isPercent()) w = containingBlock()->availableLogicalWidth(); - return padding.calcMinValue(w); + else if (padding.isViewportPercentage()) + renderView = view(); + return minimumValueForLength(padding, w, renderView); } -LayoutUnit RenderBoxModelObject::paddingStart(PaddingOptions) const +LayoutUnit RenderBoxModelObject::computedCSSPaddingStart() const { LayoutUnit w = 0; + RenderView* renderView = 0; Length padding = style()->paddingStart(); if (padding.isPercent()) w = containingBlock()->availableLogicalWidth(); - return padding.calcMinValue(w); + else if (padding.isViewportPercentage()) + renderView = view(); + return minimumValueForLength(padding, w, renderView); } -LayoutUnit RenderBoxModelObject::paddingEnd(PaddingOptions) const +LayoutUnit RenderBoxModelObject::computedCSSPaddingEnd() const { LayoutUnit w = 0; + RenderView* renderView = 0; Length padding = style()->paddingEnd(); if (padding.isPercent()) w = containingBlock()->availableLogicalWidth(); - return padding.calcMinValue(w); + else if (padding.isViewportPercentage()) + renderView = view(); + return minimumValueForLength(padding, w, renderView); } RoundedRect RenderBoxModelObject::getBackgroundRoundedRect(const LayoutRect& borderRect, InlineFlowBox* box, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHeight, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) { - RoundedRect border = style()->getRoundedBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge); + RenderView* renderView = view(); + RoundedRect border = style()->getRoundedBorderFor(borderRect, renderView, includeLogicalLeftEdge, includeLogicalRightEdge); if (box && (box->nextLineBox() || box->prevLineBox())) { - RoundedRect segmentBorder = style()->getRoundedBorderFor(LayoutRect(0, 0, inlineBoxWidth, inlineBoxHeight), includeLogicalLeftEdge, includeLogicalRightEdge); + RoundedRect segmentBorder = style()->getRoundedBorderFor(LayoutRect(0, 0, inlineBoxWidth, inlineBoxHeight), renderView, includeLogicalLeftEdge, includeLogicalRightEdge); border.setRadii(segmentBorder.radii()); } @@ -731,10 +818,10 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co context->addRoundedRectClip(border); } - LayoutUnit bLeft = includeLeftEdge ? borderLeft() : zeroLayoutUnit; - LayoutUnit bRight = includeRightEdge ? borderRight() : zeroLayoutUnit; - LayoutUnit pLeft = includeLeftEdge ? paddingLeft() : zeroLayoutUnit; - LayoutUnit pRight = includeRightEdge ? paddingRight() : zeroLayoutUnit; + int bLeft = includeLeftEdge ? borderLeft() : 0; + int bRight = includeRightEdge ? borderRight() : 0; + LayoutUnit pLeft = includeLeftEdge ? paddingLeft() : ZERO_LAYOUT_UNIT; + LayoutUnit pRight = includeRightEdge ? paddingRight() : ZERO_LAYOUT_UNIT; GraphicsContextStateSaver clipWithScrollingStateSaver(*context, clippedWithLocalScrolling); LayoutRect scrolledPaintRect = rect; @@ -757,10 +844,10 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co if (bgLayer->clip() == PaddingFillBox || bgLayer->clip() == ContentFillBox) { // Clip to the padding or content boxes as necessary. bool includePadding = bgLayer->clip() == ContentFillBox; - LayoutRect clipRect = LayoutRect(scrolledPaintRect.x() + bLeft + (includePadding ? pLeft : zeroLayoutUnit), - scrolledPaintRect.y() + borderTop() + (includePadding ? paddingTop() : zeroLayoutUnit), - scrolledPaintRect.width() - bLeft - bRight - (includePadding ? pLeft + pRight : zeroLayoutUnit), - scrolledPaintRect.height() - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : zeroLayoutUnit)); + LayoutRect clipRect = LayoutRect(scrolledPaintRect.x() + bLeft + (includePadding ? pLeft : ZERO_LAYOUT_UNIT), + scrolledPaintRect.y() + borderTop() + (includePadding ? paddingTop() : ZERO_LAYOUT_UNIT), + scrolledPaintRect.width() - bLeft - bRight - (includePadding ? pLeft + pRight : ZERO_LAYOUT_UNIT), + scrolledPaintRect.height() - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : ZERO_LAYOUT_UNIT)); backgroundClipStateSaver.save(); context->clip(clipRect); } else if (bgLayer->clip() == TextFillBox) { @@ -879,102 +966,96 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co } } -static inline LayoutUnit resolveWidthForRatio(LayoutUnit height, const FloatSize& intrinsicRatio) +static inline int resolveWidthForRatio(int height, const FloatSize& intrinsicRatio) { - // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 - return static_cast<LayoutUnit>(ceilf(height * intrinsicRatio.width() / intrinsicRatio.height())); + return ceilf(height * intrinsicRatio.width() / intrinsicRatio.height()); } -static inline LayoutUnit resolveHeightForRatio(LayoutUnit width, const FloatSize& intrinsicRatio) +static inline int resolveHeightForRatio(int width, const FloatSize& intrinsicRatio) { - // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 - return static_cast<LayoutUnit>(ceilf(width * intrinsicRatio.height() / intrinsicRatio.width())); + return ceilf(width * intrinsicRatio.height() / intrinsicRatio.width()); } -static inline LayoutSize resolveAgainstIntrinsicWidthOrHeightAndRatio(const LayoutSize& size, const FloatSize& intrinsicRatio, LayoutUnit useWidth, LayoutUnit useHeight) +static inline IntSize resolveAgainstIntrinsicWidthOrHeightAndRatio(const IntSize& size, const FloatSize& intrinsicRatio, int useWidth, int useHeight) { if (intrinsicRatio.isEmpty()) { if (useWidth) - return LayoutSize(useWidth, size.height()); - return LayoutSize(size.width(), useHeight); + return IntSize(useWidth, size.height()); + return IntSize(size.width(), useHeight); } if (useWidth) - return LayoutSize(useWidth, resolveHeightForRatio(useWidth, intrinsicRatio)); - return LayoutSize(resolveWidthForRatio(useHeight, intrinsicRatio), useHeight); + return IntSize(useWidth, resolveHeightForRatio(useWidth, intrinsicRatio)); + return IntSize(resolveWidthForRatio(useHeight, intrinsicRatio), useHeight); } -static inline LayoutSize resolveAgainstIntrinsicRatio(const LayoutSize& size, const FloatSize& intrinsicRatio) +static inline IntSize resolveAgainstIntrinsicRatio(const IntSize& size, const FloatSize& intrinsicRatio) { // Two possible solutions: (size.width(), solutionHeight) or (solutionWidth, size.height()) // "... must be assumed to be the largest dimensions..." = easiest answer: the rect with the largest surface area. - LayoutUnit solutionWidth = resolveWidthForRatio(size.height(), intrinsicRatio); - LayoutUnit solutionHeight = resolveHeightForRatio(size.width(), intrinsicRatio); + int solutionWidth = resolveWidthForRatio(size.height(), intrinsicRatio); + int solutionHeight = resolveHeightForRatio(size.width(), intrinsicRatio); if (solutionWidth <= size.width()) { if (solutionHeight <= size.height()) { // If both solutions fit, choose the one covering the larger area. - LayoutUnit areaOne = solutionWidth * size.height(); - LayoutUnit areaTwo = size.width() * solutionHeight; + int areaOne = solutionWidth * size.height(); + int areaTwo = size.width() * solutionHeight; if (areaOne < areaTwo) - return LayoutSize(size.width(), solutionHeight); - return LayoutSize(solutionWidth, size.height()); + return IntSize(size.width(), solutionHeight); + return IntSize(solutionWidth, size.height()); } // Only the first solution fits. - return LayoutSize(solutionWidth, size.height()); + return IntSize(solutionWidth, size.height()); } // Only the second solution fits, assert that. ASSERT(solutionHeight <= size.height()); - return LayoutSize(size.width(), solutionHeight); + return IntSize(size.width(), solutionHeight); } IntSize RenderBoxModelObject::calculateImageIntrinsicDimensions(StyleImage* image, const IntSize& positioningAreaSize) const { - int resolvedWidth = 0; - int resolvedHeight = 0; + // A generated image without a fixed size, will always return the container size as intrinsic size. + if (image->isGeneratedImage() && image->usesImageContainerSize()) + return IntSize(positioningAreaSize.width(), positioningAreaSize.height()); + + Length intrinsicWidth; + Length intrinsicHeight; FloatSize intrinsicRatio; + image->computeIntrinsicDimensions(this, intrinsicWidth, intrinsicHeight, intrinsicRatio); - // A generated image without a fixed size, will always return the container size as intrinsic size. - if (image->isGeneratedImage() && image->usesImageContainerSize()) { - resolvedWidth = positioningAreaSize.width(); - resolvedHeight = positioningAreaSize.height(); - } else { - Length intrinsicWidth; - Length intrinsicHeight; - image->computeIntrinsicDimensions(this, intrinsicWidth, intrinsicHeight, intrinsicRatio); - - // Intrinsic dimensions expressed as percentages must be resolved relative to the dimensions of the rectangle - // that establishes the coordinate system for the 'background-position' property. - - // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 - if (intrinsicWidth.isPercent() && intrinsicHeight.isPercent() && intrinsicRatio.isEmpty()) { - // Resolve width/height percentages against positioningAreaSize, only if no intrinsic ratio is provided. - resolvedWidth = static_cast<int>(round(positioningAreaSize.width() * intrinsicWidth.percent() / 100)); - resolvedHeight = static_cast<int>(round(positioningAreaSize.height() * intrinsicHeight.percent() / 100)); - } else { - if (intrinsicWidth.isFixed()) - resolvedWidth = static_cast<int>(intrinsicWidth.value() * style()->effectiveZoom()); - if (intrinsicHeight.isFixed()) - resolvedHeight = static_cast<int>(intrinsicHeight.value() * style()->effectiveZoom()); - } + // Intrinsic dimensions expressed as percentages must be resolved relative to the dimensions of the rectangle + // that establishes the coordinate system for the 'background-position' property. + + // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 + if (intrinsicWidth.isPercent() && intrinsicHeight.isPercent() && intrinsicRatio.isEmpty()) { + // Resolve width/height percentages against positioningAreaSize, only if no intrinsic ratio is provided. + int resolvedWidth = static_cast<int>(round(positioningAreaSize.width() * intrinsicWidth.percent() / 100)); + int resolvedHeight = static_cast<int>(round(positioningAreaSize.height() * intrinsicHeight.percent() / 100)); + return IntSize(resolvedWidth, resolvedHeight); } - if (resolvedWidth > 0 && resolvedHeight > 0) - return IntSize(resolvedWidth, resolvedHeight); + IntSize resolvedSize(intrinsicWidth.isFixed() ? intrinsicWidth.value() : 0, intrinsicHeight.isFixed() ? intrinsicHeight.value() : 0); + IntSize minimumSize(resolvedSize.width() > 0 ? 1 : 0, resolvedSize.height() > 0 ? 1 : 0); + resolvedSize.scale(style()->effectiveZoom()); + resolvedSize.clampToMinimumSize(minimumSize); + + if (!resolvedSize.isEmpty()) + return resolvedSize; // If the image has one of either an intrinsic width or an intrinsic height: // * and an intrinsic aspect ratio, then the missing dimension is calculated from the given dimension and the ratio. // * and no intrinsic aspect ratio, then the missing dimension is assumed to be the size of the rectangle that // establishes the coordinate system for the 'background-position' property. - if ((resolvedWidth && !resolvedHeight) || (!resolvedWidth && resolvedHeight)) - return resolveAgainstIntrinsicWidthOrHeightAndRatio(positioningAreaSize, intrinsicRatio, resolvedWidth, resolvedHeight); + if (resolvedSize.width() > 0 || resolvedSize.height() > 0) + return resolveAgainstIntrinsicWidthOrHeightAndRatio(positioningAreaSize, intrinsicRatio, resolvedSize.width(), resolvedSize.height()); // If the image has no intrinsic dimensions and has an intrinsic ratio the dimensions must be assumed to be the // largest dimensions at that ratio such that neither dimension exceeds the dimensions of the rectangle that // establishes the coordinate system for the 'background-position' property. - if (!resolvedWidth && !resolvedHeight && !intrinsicRatio.isEmpty()) + if (!intrinsicRatio.isEmpty()) return resolveAgainstIntrinsicRatio(positioningAreaSize, intrinsicRatio); // If the image has no intrinsic ratio either, then the dimensions must be assumed to be the rectangle that @@ -988,7 +1069,8 @@ IntSize RenderBoxModelObject::calculateFillTileSize(const FillLayer* fillLayer, EFillSizeType type = fillLayer->size().type; IntSize imageIntrinsicSize = calculateImageIntrinsicDimensions(image, positioningAreaSize); - + imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScaleFactor()); + RenderView* renderView = view(); switch (type) { case SizeLength: { int w = positioningAreaSize.width(); @@ -999,13 +1081,13 @@ IntSize RenderBoxModelObject::calculateFillTileSize(const FillLayer* fillLayer, if (layerWidth.isFixed()) w = layerWidth.value(); - else if (layerWidth.isPercent()) - w = layerWidth.calcValue(positioningAreaSize.width()); + else if (layerWidth.isPercent() || layerHeight.isViewportPercentage()) + w = valueForLength(layerWidth, positioningAreaSize.width(), renderView); if (layerHeight.isFixed()) h = layerHeight.value(); - else if (layerHeight.isPercent()) - h = layerHeight.calcValue(positioningAreaSize.height()); + else if (layerHeight.isPercent() || layerHeight.isViewportPercentage()) + h = valueForLength(layerHeight, positioningAreaSize.height(), renderView); // If one of the values is auto we have to use the appropriate // scale to maintain our aspect ratio. @@ -1083,6 +1165,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil LayoutUnit left = 0; LayoutUnit top = 0; IntSize positioningAreaSize; + IntRect snappedPaintRect = pixelSnappedIntRect(paintRect); // Determine the background positioning area and set destRect to the background painting area. // destRect will be adjusted later if the background is non-repeating. @@ -1099,7 +1182,7 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil #endif if (!fixedAttachment) { - geometry.setDestRect(paintRect); + geometry.setDestRect(snappedPaintRect); LayoutUnit right = 0; LayoutUnit bottom = 0; @@ -1121,11 +1204,13 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil // its margins. Since those were added in already, we have to factor them out when computing // the background positioning area. if (isRoot()) { - positioningAreaSize = LayoutSize(toRenderBox(this)->width() - left - right, toRenderBox(this)->height() - top - bottom); + positioningAreaSize = IntSize(snapSizeToPixel(toRenderBox(this)->width() - left - right, toRenderBox(this)->x()), + snapSizeToPixel(toRenderBox(this)->height() - top - bottom, toRenderBox(this)->y())); left += marginLeft(); top += marginTop(); } else - positioningAreaSize = LayoutSize(paintRect.width() - left - right, paintRect.height() - top - bottom); + positioningAreaSize = IntSize(snapSizeToPixel(paintRect.width() - left - right, paintRect.x()), + snapSizeToPixel(paintRect.height() - top - bottom, paintRect.y())); } else { geometry.setDestRect(pixelSnappedIntRect(viewRect())); positioningAreaSize = geometry.destRect().size(); @@ -1137,33 +1222,34 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil EFillRepeat backgroundRepeatX = fillLayer->repeatX(); EFillRepeat backgroundRepeatY = fillLayer->repeatY(); + RenderView* renderView = view(); - LayoutUnit xPosition = fillLayer->xPosition().calcMinValue(positioningAreaSize.width() - geometry.tileSize().width(), true); + LayoutUnit xPosition = minimumValueForLength(fillLayer->xPosition(), positioningAreaSize.width() - geometry.tileSize().width(), renderView, true); if (backgroundRepeatX == RepeatFill) - geometry.setPhaseX(geometry.tileSize().width() ? layoutMod(geometry.tileSize().width() - (xPosition + left), geometry.tileSize().width()) : LayoutUnit(0)); + geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - roundToInt(xPosition + left) % geometry.tileSize().width() : 0); else geometry.setNoRepeatX(xPosition + left); - LayoutUnit yPosition = fillLayer->yPosition().calcMinValue(positioningAreaSize.height() - geometry.tileSize().height(), true); + LayoutUnit yPosition = minimumValueForLength(fillLayer->yPosition(), positioningAreaSize.height() - geometry.tileSize().height(), renderView, true); if (backgroundRepeatY == RepeatFill) - geometry.setPhaseY(geometry.tileSize().height() ? layoutMod(geometry.tileSize().height() - (yPosition + top), geometry.tileSize().height()) : LayoutUnit(0)); + geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - roundToInt(yPosition + top) % geometry.tileSize().height() : 0); else geometry.setNoRepeatY(yPosition + top); if (fixedAttachment) - geometry.useFixedAttachment(paintRect.location()); + geometry.useFixedAttachment(snappedPaintRect.location()); - geometry.clip(paintRect); + geometry.clip(snappedPaintRect); geometry.setDestOrigin(geometry.destRect().location()); } -static LayoutUnit computeBorderImageSide(Length borderSlice, LayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent) +static LayoutUnit computeBorderImageSide(Length borderSlice, LayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent, RenderView* renderView) { if (borderSlice.isRelative()) return borderSlice.value() * borderSide; if (borderSlice.isAuto()) return imageSide; - return borderSlice.calcValue(boxExtent); + return valueForLength(borderSlice, boxExtent, renderView); } bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, const LayoutRect& rect, const RenderStyle* style, @@ -1191,7 +1277,7 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, LayoutUnit bottomWithOutset = rect.maxY() + bottomOutset; LayoutUnit leftWithOutset = rect.x() - leftOutset; LayoutUnit rightWithOutset = rect.maxX() + rightOutset; - LayoutRect borderImageRect = LayoutRect(leftWithOutset, topWithOutset, rightWithOutset - leftWithOutset, bottomWithOutset - topWithOutset); + IntRect borderImageRect = pixelSnappedIntRect(leftWithOutset, topWithOutset, rightWithOutset - leftWithOutset, bottomWithOutset - topWithOutset); IntSize imageSize = calculateImageIntrinsicDimensions(styleImage, borderImageRect.size()); @@ -1200,19 +1286,21 @@ bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, int imageWidth = imageSize.width() / style->effectiveZoom(); int imageHeight = imageSize.height() / style->effectiveZoom(); + RenderView* renderView = view(); - int topSlice = min<int>(imageHeight, ninePieceImage.imageSlices().top().calcValue(imageHeight)); - int rightSlice = min<int>(imageWidth, ninePieceImage.imageSlices().right().calcValue(imageWidth)); - int bottomSlice = min<int>(imageHeight, ninePieceImage.imageSlices().bottom().calcValue(imageHeight)); - int leftSlice = min<int>(imageWidth, ninePieceImage.imageSlices().left().calcValue(imageWidth)); + float imageScaleFactor = styleImage->imageScaleFactor(); + int topSlice = min<int>(imageHeight, valueForLength(ninePieceImage.imageSlices().top(), imageHeight, renderView)) * imageScaleFactor; + int rightSlice = min<int>(imageWidth, valueForLength(ninePieceImage.imageSlices().right(), imageWidth, renderView)) * imageScaleFactor; + int bottomSlice = min<int>(imageHeight, valueForLength(ninePieceImage.imageSlices().bottom(), imageHeight, renderView)) * imageScaleFactor; + int leftSlice = min<int>(imageWidth, valueForLength(ninePieceImage.imageSlices().left(), imageWidth, renderView)) * imageScaleFactor; ENinePieceImageRule hRule = ninePieceImage.horizontalRule(); ENinePieceImageRule vRule = ninePieceImage.verticalRule(); - - LayoutUnit topWidth = computeBorderImageSide(ninePieceImage.borderSlices().top(), style->borderTopWidth(), topSlice, borderImageRect.height()); - LayoutUnit rightWidth = computeBorderImageSide(ninePieceImage.borderSlices().right(), style->borderRightWidth(), rightSlice, borderImageRect.width()); - LayoutUnit bottomWidth = computeBorderImageSide(ninePieceImage.borderSlices().bottom(), style->borderBottomWidth(), bottomSlice, borderImageRect.height()); - LayoutUnit leftWidth = computeBorderImageSide(ninePieceImage.borderSlices().left(), style->borderLeftWidth(), leftSlice, borderImageRect.width()); + + LayoutUnit topWidth = computeBorderImageSide(ninePieceImage.borderSlices().top(), style->borderTopWidth(), topSlice, borderImageRect.height(), renderView); + LayoutUnit rightWidth = computeBorderImageSide(ninePieceImage.borderSlices().right(), style->borderRightWidth(), rightSlice, borderImageRect.width(), renderView); + LayoutUnit bottomWidth = computeBorderImageSide(ninePieceImage.borderSlices().bottom(), style->borderBottomWidth(), bottomSlice, borderImageRect.height(), renderView); + LayoutUnit leftWidth = computeBorderImageSide(ninePieceImage.borderSlices().left(), style->borderLeftWidth(), leftSlice, borderImageRect.width(), renderView); // Reduce the widths if they're too large. // The spec says: Given Lwidth as the width of the border image area, Lheight as its height, and Wside as the border image width @@ -1755,27 +1843,27 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& return; BorderEdge edges[4]; - getBorderEdgeInfo(edges, includeLogicalLeftEdge, includeLogicalRightEdge); - - RoundedRect outerBorder = style->getRoundedBorderFor(rect, includeLogicalLeftEdge, includeLogicalRightEdge); + getBorderEdgeInfo(edges, style, includeLogicalLeftEdge, includeLogicalRightEdge); + RoundedRect outerBorder = style->getRoundedBorderFor(rect, view(), includeLogicalLeftEdge, includeLogicalRightEdge); RoundedRect innerBorder = style->getRoundedInnerBorderFor(rect, includeLogicalLeftEdge, includeLogicalRightEdge); bool haveAlphaColor = false; bool haveAllSolidEdges = true; - bool allEdgesVisible = true; + bool haveAllDoubleEdges = true; + int numEdgesVisible = 4; bool allEdgesShareColor = true; int firstVisibleEdge = -1; for (int i = BSTop; i <= BSLeft; ++i) { const BorderEdge& currEdge = edges[i]; if (currEdge.presentButInvisible()) { - allEdgesVisible = false; + --numEdgesVisible; allEdgesShareColor = false; continue; } if (!currEdge.width) { - allEdgesVisible = false; + --numEdgesVisible; continue; } @@ -1789,6 +1877,9 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& if (currEdge.style != SOLID) haveAllSolidEdges = false; + + if (currEdge.style != DOUBLE) + haveAllDoubleEdges = false; } // If no corner intersects the clip region, we can pretend outerBorder is @@ -1797,9 +1888,10 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& outerBorder.setRadii(RoundedRect::Radii()); // isRenderable() check avoids issue described in https://bugs.webkit.org/show_bug.cgi?id=38787 - if (haveAllSolidEdges && allEdgesShareColor && innerBorder.isRenderable()) { - // Fast path for drawing all solid edges. - if (allEdgesVisible && (outerBorder.isRounded() || haveAlphaColor)) { + if ((haveAllSolidEdges || haveAllDoubleEdges) && allEdgesShareColor && innerBorder.isRenderable()) { + // Fast path for drawing all solid edges and all unrounded double edges + if (numEdgesVisible == 4 && (outerBorder.isRounded() || haveAlphaColor) + && (haveAllSolidEdges || (!outerBorder.isRounded() && !innerBorder.isRounded()))) { Path path; if (outerBorder.isRounded() && bleedAvoidance != BackgroundBleedUseTransparencyLayer) @@ -1807,6 +1899,45 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& else path.addRect(outerBorder.rect()); + if (haveAllDoubleEdges) { + IntRect innerThirdRect = outerBorder.rect(); + IntRect outerThirdRect = outerBorder.rect(); + for (int side = BSTop; side <= BSLeft; ++side) { + int outerWidth; + int innerWidth; + edges[side].getDoubleBorderStripeWidths(outerWidth, innerWidth); + + if (side == BSTop) { + innerThirdRect.shiftYEdgeTo(innerThirdRect.y() + innerWidth); + outerThirdRect.shiftYEdgeTo(outerThirdRect.y() + outerWidth); + } else if (side == BSBottom) { + innerThirdRect.setHeight(innerThirdRect.height() - innerWidth); + outerThirdRect.setHeight(outerThirdRect.height() - outerWidth); + } else if (side == BSLeft) { + innerThirdRect.shiftXEdgeTo(innerThirdRect.x() + innerWidth); + outerThirdRect.shiftXEdgeTo(outerThirdRect.x() + outerWidth); + } else { + innerThirdRect.setWidth(innerThirdRect.width() - innerWidth); + outerThirdRect.setWidth(outerThirdRect.width() - outerWidth); + } + } + + RoundedRect outerThird = outerBorder; + RoundedRect innerThird = innerBorder; + innerThird.setRect(innerThirdRect); + outerThird.setRect(outerThirdRect); + + if (outerThird.isRounded() && bleedAvoidance != BackgroundBleedUseTransparencyLayer) + path.addRoundedRect(outerThird); + else + path.addRect(outerThird.rect()); + + if (innerThird.isRounded() && bleedAvoidance != BackgroundBleedUseTransparencyLayer) + path.addRoundedRect(innerThird); + else + path.addRect(innerThird.rect()); + } + if (innerBorder.isRounded()) path.addRoundedRect(innerBorder); else @@ -1818,7 +1949,7 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& return; } // Avoid creating transparent layers - if (!allEdgesVisible && !outerBorder.isRounded() && haveAlphaColor) { + if (haveAllSolidEdges && numEdgesVisible != 4 && !outerBorder.isRounded() && haveAlphaColor) { Path path; for (int i = BSTop; i <= BSLeft; ++i) { @@ -1848,7 +1979,8 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& graphicsContext->clipOutRoundedRect(innerBorder); } - bool antialias = shouldAntialiasLines(graphicsContext); + // If only one edge visible antialiasing doesn't create seams + bool antialias = shouldAntialiasLines(graphicsContext) || numEdgesVisible == 1; if (haveAlphaColor) paintTranslucentBorderSides(graphicsContext, style, outerBorder, innerBorder, edges, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias); else @@ -2042,7 +2174,7 @@ void RenderBoxModelObject::paintBorder(const PaintInfo& info, const IntRect& rec GraphicsContextStateSaver stateSaver(*graphicsContext, false); if (style->hasBorderRadius()) { - border.includeLogicalEdges(style->getRoundedBorderFor(border.rect()).radii(), + border.includeLogicalEdges(style->getRoundedBorderFor(border.rect(), view()).radii(), horizontal, includeLogicalLeftEdge, includeLogicalRightEdge); if (border.isRounded()) { stateSaver.save(); @@ -2560,9 +2692,8 @@ void RenderBoxModelObject::clipBorderSideForComplexInnerPath(GraphicsContext* gr graphicsContext->clipOutRoundedRect(calculateAdjustedInnerBorder(innerBorder, side)); } -void RenderBoxModelObject::getBorderEdgeInfo(BorderEdge edges[], bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const +void RenderBoxModelObject::getBorderEdgeInfo(BorderEdge edges[], const RenderStyle* style, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const { - const RenderStyle* style = this->style(); bool horizontal = style->isHorizontalWritingMode(); edges[BSTop] = BorderEdge(style->borderTopWidth(), @@ -2593,7 +2724,7 @@ void RenderBoxModelObject::getBorderEdgeInfo(BorderEdge edges[], bool includeLog bool RenderBoxModelObject::borderObscuresBackgroundEdge(const FloatSize& contextScale) const { BorderEdge edges[4]; - getBorderEdgeInfo(edges); + getBorderEdgeInfo(edges, style()); for (int i = BSTop; i <= BSLeft; ++i) { const BorderEdge& currEdge = edges[i]; @@ -2616,7 +2747,7 @@ bool RenderBoxModelObject::borderObscuresBackground() const return false; BorderEdge edges[4]; - getBorderEdgeInfo(edges); + getBorderEdgeInfo(edges, style()); for (int i = BSTop; i <= BSLeft; ++i) { const BorderEdge& currEdge = edges[i]; @@ -2674,16 +2805,16 @@ bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(BackgroundBleedA return true; } -static inline LayoutRect areaCastingShadowInHole(const LayoutRect& holeRect, int shadowBlur, int shadowSpread, const LayoutSize& shadowOffset) +static inline IntRect areaCastingShadowInHole(const IntRect& holeRect, int shadowBlur, int shadowSpread, const IntSize& shadowOffset) { - LayoutRect bounds(holeRect); + IntRect bounds(holeRect); bounds.inflate(shadowBlur); if (shadowSpread < 0) bounds.inflate(-shadowSpread); - LayoutRect offsetBounds = bounds; + IntRect offsetBounds = bounds; offsetBounds.move(-shadowOffset); return unionRect(bounds, offsetBounds); } @@ -2696,7 +2827,7 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec return; RoundedRect border = (shadowStyle == Inset) ? s->getRoundedInnerBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge) - : s->getRoundedBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge); + : s->getRoundedBorderFor(paintRect, view(), includeLogicalLeftEdge, includeLogicalRightEdge); bool hasBorderRadius = s->hasBorderRadius(); bool isHorizontal = s->isHorizontalWritingMode(); @@ -2706,9 +2837,9 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec if (shadow->style() != shadowStyle) continue; - LayoutSize shadowOffset(shadow->x(), shadow->y()); - LayoutUnit shadowBlur = shadow->blur(); - LayoutUnit shadowSpread = shadow->spread(); + IntSize shadowOffset(shadow->x(), shadow->y()); + int shadowBlur = shadow->blur(); + int shadowSpread = shadow->spread(); if (shadowOffset.isZero() && !shadowBlur && !shadowSpread) continue; @@ -2721,7 +2852,7 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec if (fillRect.isEmpty()) continue; - LayoutRect shadowRect(border.rect()); + IntRect shadowRect(border.rect()); shadowRect.inflate(shadowBlur + shadowSpread); shadowRect.move(shadowOffset); @@ -2730,7 +2861,7 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec // Move the fill just outside the clip, adding 1 pixel separation so that the fill does not // bleed in (due to antialiasing) if the context is transformed. - LayoutSize extraOffset(paintRect.width() + max<LayoutUnit>(0, shadowOffset.width()) + shadowBlur + 2 * shadowSpread + 1, 0); + IntSize extraOffset(paintRect.pixelSnappedWidth() + max(0, shadowOffset.width()) + shadowBlur + 2 * shadowSpread + 1, 0); shadowOffset -= extraOffset; fillRect.move(extraOffset); @@ -2752,7 +2883,7 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec if (!rectToClipOut.isEmpty()) context->clipOutRoundedRect(rectToClipOut); - RoundedRect influenceRect(pixelSnappedIntRect(shadowRect), border.radii()); + RoundedRect influenceRect(shadowRect, border.radii()); influenceRect.expandRadii(2 * shadowBlur + shadowSpread); if (allCornersClippedOut(influenceRect, info.rect)) context->fillRect(fillRect.rect(), Color::black, s->colorSpace()); @@ -2761,7 +2892,7 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec context->fillRoundedRect(fillRect, Color::black, s->colorSpace()); } } else { - LayoutRect rectToClipOut = border.rect(); + IntRect rectToClipOut = border.rect(); // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time // when painting the shadow. On the other hand, it introduces subpixel gaps along the @@ -2776,12 +2907,12 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec } if (!rectToClipOut.isEmpty()) - context->clipOut(pixelSnappedIntRect(rectToClipOut)); + context->clipOut(rectToClipOut); context->fillRect(fillRect.rect(), Color::black, s->colorSpace()); } } else { // Inset shadow. - LayoutRect holeRect(border.rect()); + IntRect holeRect(border.rect()); holeRect.inflate(-shadowSpread); if (holeRect.isEmpty()) { @@ -2794,24 +2925,24 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec if (!includeLogicalLeftEdge) { if (isHorizontal) { - holeRect.move(-max<LayoutUnit>(shadowOffset.width(), 0) - shadowBlur, 0); - holeRect.setWidth(holeRect.width() + max<LayoutUnit>(shadowOffset.width(), 0) + shadowBlur); + holeRect.move(-max(shadowOffset.width(), 0) - shadowBlur, 0); + holeRect.setWidth(holeRect.width() + max(shadowOffset.width(), 0) + shadowBlur); } else { - holeRect.move(0, -max<LayoutUnit>(shadowOffset.height(), 0) - shadowBlur); - holeRect.setHeight(holeRect.height() + max<LayoutUnit>(shadowOffset.height(), 0) + shadowBlur); + holeRect.move(0, -max(shadowOffset.height(), 0) - shadowBlur); + holeRect.setHeight(holeRect.height() + max(shadowOffset.height(), 0) + shadowBlur); } } if (!includeLogicalRightEdge) { if (isHorizontal) - holeRect.setWidth(holeRect.width() - min<LayoutUnit>(shadowOffset.width(), 0) + shadowBlur); + holeRect.setWidth(holeRect.width() - min(shadowOffset.width(), 0) + shadowBlur); else - holeRect.setHeight(holeRect.height() - min<LayoutUnit>(shadowOffset.height(), 0) + shadowBlur); + holeRect.setHeight(holeRect.height() - min(shadowOffset.height(), 0) + shadowBlur); } Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255); - LayoutRect outerRect = areaCastingShadowInHole(border.rect(), shadowBlur, shadowSpread, shadowOffset); - RoundedRect roundedHole(pixelSnappedIntRect(holeRect), border.radii()); + IntRect outerRect = areaCastingShadowInHole(border.rect(), shadowBlur, shadowSpread, shadowOffset); + RoundedRect roundedHole(holeRect, border.radii()); GraphicsContextStateSaver stateSaver(*context); if (hasBorderRadius) { @@ -2822,7 +2953,7 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec } else context->clip(border.rect()); - LayoutSize extraOffset(2 * paintRect.width() + max<LayoutUnit>(0, shadowOffset.width()) + shadowBlur - 2 * shadowSpread + 1, 0); + IntSize extraOffset(2 * paintRect.pixelSnappedWidth() + max(0, shadowOffset.width()) + shadowBlur - 2 * shadowSpread + 1, 0); context->translate(extraOffset.width(), extraOffset.height()); shadowOffset -= extraOffset; @@ -2831,7 +2962,7 @@ void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec else context->setShadow(shadowOffset, shadowBlur, shadowColor, s->colorSpace()); - context->fillRectWithRoundedHole(pixelSnappedIntRect(outerRect), roundedHole, fillColor, s->colorSpace()); + context->fillRectWithRoundedHole(outerRect, roundedHole, fillColor, s->colorSpace()); } } } diff --git a/Source/WebCore/rendering/RenderBoxModelObject.h b/Source/WebCore/rendering/RenderBoxModelObject.h index 553584769..8e7fdb088 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.h +++ b/Source/WebCore/rendering/RenderBoxModelObject.h @@ -40,7 +40,15 @@ enum BackgroundBleedAvoidance { BackgroundBleedUseTransparencyLayer }; -enum PaddingOptions { IncludeIntrinsicPadding, ExcludeIntrinsicPadding }; +enum ContentChangeType { + ImageChanged, + MaskImageChanged, + CanvasChanged, + VideoChanged, + FullScreenChanged +}; + +class KeyframeList; // This class is the base for all objects that adhere to the CSS box model as described // at http://www.w3.org/TR/CSS21/box.html @@ -64,7 +72,6 @@ public: int pixelSnappedOffsetLeft() const { return roundToInt(offsetLeft()); } int pixelSnappedOffsetTop() const { return roundToInt(offsetTop()); } - // FIXME: The implementation for these functions will change once we move to subpixel layout. See bug 60318. int pixelSnappedOffsetWidth() const; int pixelSnappedOffsetHeight() const; @@ -74,20 +81,31 @@ public: bool hasSelfPaintingLayer() const; RenderLayer* layer() const { return m_layer; } - virtual bool requiresLayer() const { return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasTransform() || hasMask() || hasReflection() || hasFilter() || style()->specifiesColumns(); } + virtual bool requiresLayer() const { return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasTransform() || hasHiddenBackface() || hasMask() || hasReflection() || hasFilter() || style()->specifiesColumns(); } // This will work on inlines to return the bounding box of all of the lines' border boxes. - virtual LayoutRect borderBoundingBox() const = 0; - - // Virtual since table cells override - virtual LayoutUnit paddingTop(PaddingOptions = IncludeIntrinsicPadding) const; - virtual LayoutUnit paddingBottom(PaddingOptions = IncludeIntrinsicPadding) const; - virtual LayoutUnit paddingLeft(PaddingOptions = IncludeIntrinsicPadding) const; - virtual LayoutUnit paddingRight(PaddingOptions = IncludeIntrinsicPadding) const; - virtual LayoutUnit paddingBefore(PaddingOptions = IncludeIntrinsicPadding) const; - virtual LayoutUnit paddingAfter(PaddingOptions = IncludeIntrinsicPadding) const; - virtual LayoutUnit paddingStart(PaddingOptions = IncludeIntrinsicPadding) const; - virtual LayoutUnit paddingEnd(PaddingOptions = IncludeIntrinsicPadding) const; + virtual IntRect borderBoundingBox() const = 0; + + // These return the CSS computed padding values. + LayoutUnit computedCSSPaddingTop() const; + LayoutUnit computedCSSPaddingBottom() const; + LayoutUnit computedCSSPaddingLeft() const; + LayoutUnit computedCSSPaddingRight() const; + LayoutUnit computedCSSPaddingBefore() const; + LayoutUnit computedCSSPaddingAfter() const; + LayoutUnit computedCSSPaddingStart() const; + LayoutUnit computedCSSPaddingEnd() const; + + // These functions are used during layout. Table cells and the MathML + // code override them to include some extra intrinsic padding. + virtual LayoutUnit paddingTop() const { return computedCSSPaddingTop(); } + virtual LayoutUnit paddingBottom() const { return computedCSSPaddingBottom(); } + virtual LayoutUnit paddingLeft() const { return computedCSSPaddingLeft(); } + virtual LayoutUnit paddingRight() const { return computedCSSPaddingRight(); } + virtual LayoutUnit paddingBefore() const { return computedCSSPaddingBefore(); } + virtual LayoutUnit paddingAfter() const { return computedCSSPaddingAfter(); } + virtual LayoutUnit paddingStart() const { return computedCSSPaddingStart(); } + virtual LayoutUnit paddingEnd() const { return computedCSSPaddingEnd(); } virtual int borderTop() const { return style()->borderTopWidth(); } virtual int borderBottom() const { return style()->borderBottomWidth(); } @@ -146,6 +164,21 @@ public: virtual void setSelectionState(SelectionState s); +#if USE(ACCELERATED_COMPOSITING) + void contentChanged(ContentChangeType); + bool hasAcceleratedCompositing() const; + + bool startTransition(double, CSSPropertyID, const RenderStyle* fromStyle, const RenderStyle* toStyle); + void transitionPaused(double timeOffset, CSSPropertyID); + void transitionFinished(CSSPropertyID); + + bool startAnimation(double timeOffset, const Animation*, const KeyframeList& keyframes); + void animationPaused(double timeOffset, const String& name); + void animationFinished(const String& name); + + void suspendAnimations(double time = 0); +#endif + protected: virtual void willBeDestroyed(); @@ -195,7 +228,7 @@ protected: }; void calculateBackgroundImageGeometry(const FillLayer*, const LayoutRect& paintRect, BackgroundImageGeometry&); - void getBorderEdgeInfo(class BorderEdge[], bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; + void getBorderEdgeInfo(class BorderEdge[], const RenderStyle*, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; bool borderObscuresBackgroundEdge(const FloatSize& contextScale) const; bool borderObscuresBackground() const; @@ -211,8 +244,6 @@ public: RenderObject* firstLetterRemainingText() const; void setFirstLetterRemainingText(RenderObject*); - void ensureLayer(); - private: virtual bool isBoxModelObject() const { return true; } diff --git a/Source/WebCore/rendering/RenderButton.cpp b/Source/WebCore/rendering/RenderButton.cpp index 380c5da35..5477f9e50 100644 --- a/Source/WebCore/rendering/RenderButton.cpp +++ b/Source/WebCore/rendering/RenderButton.cpp @@ -49,8 +49,7 @@ void RenderButton::addChild(RenderObject* newChild, RenderObject* beforeChild) if (!m_inner) { // Create an anonymous block. ASSERT(!firstChild()); - bool isFlexibleBox = style()->display() == BOX || style()->display() == INLINE_BOX; - m_inner = createAnonymousBlock(isFlexibleBox); + m_inner = createAnonymousBlock(style()->display()); setupInnerStyle(m_inner->style()); RenderDeprecatedFlexibleBox::addChild(m_inner); } diff --git a/Source/WebCore/rendering/RenderButton.h b/Source/WebCore/rendering/RenderButton.h index fb94af988..5be62b012 100644 --- a/Source/WebCore/rendering/RenderButton.h +++ b/Source/WebCore/rendering/RenderButton.h @@ -40,6 +40,8 @@ public: virtual const char* renderName() const { return "RenderButton"; } virtual bool isRenderButton() const { return true; } + virtual bool canBeSelectionLeaf() const OVERRIDE { return node() && node()->rendererIsEditable(); } + virtual void addChild(RenderObject* newChild, RenderObject *beforeChild = 0); virtual void removeChild(RenderObject*); virtual void removeLeftoverAnonymousBlock(RenderBlock*) { } diff --git a/Source/WebCore/rendering/RenderCounter.cpp b/Source/WebCore/rendering/RenderCounter.cpp index 0807ea9dd..29c0f1ccb 100644 --- a/Source/WebCore/rendering/RenderCounter.cpp +++ b/Source/WebCore/rendering/RenderCounter.cpp @@ -41,7 +41,7 @@ namespace WebCore { using namespace HTMLNames; typedef HashMap<RefPtr<AtomicStringImpl>, RefPtr<CounterNode> > CounterMap; -typedef HashMap<const RenderObject*, CounterMap*> CounterMaps; +typedef HashMap<const RenderObject*, OwnPtr<CounterMap> > CounterMaps; static CounterNode* makeCounterNode(RenderObject*, const AtomicString& identifier, bool alwaysCreateCounter); @@ -440,7 +440,7 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id nodeMap = counterMaps().get(object); else { nodeMap = new CounterMap; - counterMaps().set(object, nodeMap); + counterMaps().set(object, adoptPtr(nodeMap)); object->setHasCounterNodeMap(true); } nodeMap->set(identifier.impl(), newNode); @@ -563,14 +563,13 @@ void RenderCounter::destroyCounterNodes(RenderObject* owner) CounterMaps::iterator mapsIterator = maps.find(owner); if (mapsIterator == maps.end()) return; - CounterMap* map = mapsIterator->second; + CounterMap* map = mapsIterator->second.get(); CounterMap::const_iterator end = map->end(); for (CounterMap::const_iterator it = map->begin(); it != end; ++it) { AtomicString identifier(it->first.get()); destroyCounterNodeWithoutMapRemoval(identifier, it->second.get()); } maps.remove(mapsIterator); - delete map; owner->setHasCounterNodeMap(false); } diff --git a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp index add01a0c2..b956d3946 100644 --- a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp +++ b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp @@ -218,7 +218,7 @@ void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths() setPreferredLogicalWidthsDirty(false); } -void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight, BlockLayoutPass layoutPass) +void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit) { ASSERT(needsLayout()); @@ -272,7 +272,7 @@ void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit if (previousSize.height() != height()) relayoutChildren = true; - bool needAnotherLayoutPass = layoutPositionedObjects(relayoutChildren || isRoot()); + layoutPositionedObjects(relayoutChildren || isRoot()); computeRegionRangeForBlock(); @@ -305,16 +305,13 @@ void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit // Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. - updateScrollInfoAfterLayout(); + if (hasOverflowClip()) + layer()->updateScrollInfoAfterLayout(); // Repaint with our new bounds if they are different from our old bounds. repainter.repaintAfterLayout(); - if (needAnotherLayoutPass && layoutPass == NormalLayoutPass) { - setChildNeedsLayout(true, false); - layoutBlock(false, pageLogicalHeight); - } else - setNeedsLayout(false); + setNeedsLayout(false); } // The first walk over our kids is to find out if we have any flexible children. @@ -327,7 +324,7 @@ static void gatherFlexChildrenInfo(FlexBoxIterator& iterator, bool relayoutChild // may have changed, and we need to reallocate space. child->clearOverrideSize(); if (!relayoutChildren) - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); haveFlex = true; unsigned int flexGroup = child->style()->boxFlexGroup(); if (lowestFlexGroup == 0) @@ -374,7 +371,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren) for (RenderBox* child = iterator.first(); child; child = iterator.next()) { // make sure we relayout children if we need it. if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))) - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); if (child->isPositioned()) continue; @@ -431,7 +428,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren) if (childLayer->staticBlockPosition() != yPos) { childLayer->setStaticBlockPosition(yPos); if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); } continue; } else if (child->style()->visibility() == COLLAPSE) { @@ -448,7 +445,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren) LayoutUnit oldChildHeight = child->height(); child->computeLogicalHeight(); if (oldChildHeight != child->height()) - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); if (!child->needsLayout()) child->markForPaginationRelayoutIfNeeded(); @@ -517,7 +514,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren) for (RenderBox* child = iterator.first(); child; child = iterator.next()) { LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i); if (allowedFlex) { - LayoutUnit projectedFlex = (allowedFlex == numeric_limits<LayoutUnit>::max()) ? allowedFlex : LayoutUnit(allowedFlex * (totalFlex / child->style()->boxFlex())); + LayoutUnit projectedFlex = (allowedFlex == MAX_LAYOUT_UNIT) ? allowedFlex : LayoutUnit(allowedFlex * (totalFlex / child->style()->boxFlex())); spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex); } } @@ -562,7 +559,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren) } } } - } while (groupRemainingSpace); + } while (absoluteValue(groupRemainingSpace) >= 1); } // We didn't find any children that could grow. @@ -663,7 +660,7 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren) for (RenderBox* child = iterator.first(); child; child = iterator.next()) { // Make sure we relayout children if we need it. if (!haveLineClamp && (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())))) - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); if (child->isPositioned()) { child->containingBlock()->insertPositionedObject(child); @@ -672,7 +669,7 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren) if (childLayer->staticBlockPosition() != height()) { childLayer->setStaticBlockPosition(height()); if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); } continue; } else if (child->style()->visibility() == COLLAPSE) { @@ -771,7 +768,7 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren) for (RenderBox* child = iterator.first(); child; child = iterator.next()) { LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i); if (allowedFlex) { - LayoutUnit projectedFlex = (allowedFlex == numeric_limits<LayoutUnit>::max()) ? allowedFlex : static_cast<LayoutUnit>(allowedFlex * (totalFlex / child->style()->boxFlex())); + LayoutUnit projectedFlex = (allowedFlex == MAX_LAYOUT_UNIT) ? allowedFlex : static_cast<LayoutUnit>(allowedFlex * (totalFlex / child->style()->boxFlex())); spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex); } } @@ -813,7 +810,7 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren) } } } - } while (groupRemainingSpace); + } while (absoluteValue(groupRemainingSpace) >= 1); } // We didn't find any children that could grow. @@ -885,7 +882,7 @@ void RenderDeprecatedFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())) || (child->style()->height().isAuto() && child->isBlockFlow())) { - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); // Dirty all the positioned objects. if (child->isRenderBlock()) { @@ -918,7 +915,7 @@ void RenderDeprecatedFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool if (newHeight == child->height()) continue; - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); child->setOverrideHeight(newHeight); m_flexingChildren = true; child->layoutIfNeeded(); @@ -1000,7 +997,7 @@ LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool if (expanding) { if (isHorizontal()) { // FIXME: For now just handle fixed values. - LayoutUnit maxWidth = numeric_limits<LayoutUnit>::max(); + LayoutUnit maxWidth = MAX_LAYOUT_UNIT; LayoutUnit width = child->overrideWidth() - child->borderAndPaddingWidth(); if (!child->style()->maxWidth().isUndefined() && child->style()->maxWidth().isFixed()) maxWidth = child->style()->maxWidth().value(); @@ -1008,16 +1005,16 @@ LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool maxWidth = child->maxPreferredLogicalWidth(); else if (child->style()->maxWidth().type() == MinIntrinsic) maxWidth = child->minPreferredLogicalWidth(); - if (maxWidth == numeric_limits<LayoutUnit>::max()) + if (maxWidth == MAX_LAYOUT_UNIT) return maxWidth; return max<LayoutUnit>(0, maxWidth - width); } else { // FIXME: For now just handle fixed values. - LayoutUnit maxHeight = numeric_limits<LayoutUnit>::max(); + LayoutUnit maxHeight = MAX_LAYOUT_UNIT; LayoutUnit height = child->overrideHeight() - child->borderAndPaddingHeight(); if (!child->style()->maxHeight().isUndefined() && child->style()->maxHeight().isFixed()) maxHeight = child->style()->maxHeight().value(); - if (maxHeight == numeric_limits<LayoutUnit>::max()) + if (maxHeight == MAX_LAYOUT_UNIT) return maxHeight; return max<LayoutUnit>(0, maxHeight - height); } diff --git a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.h b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.h index 9a42bd401..4d912f430 100644 --- a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.h +++ b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.h @@ -40,7 +40,7 @@ public: void calcHorizontalPrefWidths(); void calcVerticalPrefWidths(); - virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageHeight = 0, BlockLayoutPass = NormalLayoutPass); + virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageHeight = 0); void layoutHorizontalBox(bool relayoutChildren); void layoutVerticalBox(bool relayoutChildren); diff --git a/Source/WebCore/rendering/RenderDetailsMarker.cpp b/Source/WebCore/rendering/RenderDetailsMarker.cpp index bcffaac1c..c36cdd588 100644 --- a/Source/WebCore/rendering/RenderDetailsMarker.cpp +++ b/Source/WebCore/rendering/RenderDetailsMarker.cpp @@ -21,7 +21,7 @@ #include "config.h" #include "RenderDetailsMarker.h" -#if ENABLE(DETAILS) +#if ENABLE(DETAILS) || ENABLE(CALENDAR_PICKER) #include "Element.h" #include "GraphicsContext.h" @@ -105,10 +105,10 @@ Path RenderDetailsMarker::getCanonicalPath() const return Path(); } -Path RenderDetailsMarker::getPath(const IntPoint& origin) const +Path RenderDetailsMarker::getPath(const LayoutPoint& origin) const { Path result = getCanonicalPath(); - result.transform(AffineTransform().scale(logicalHeight())); + result.transform(AffineTransform().scale(contentWidth(), contentHeight())); result.translate(FloatSize(origin.x(), origin.y())); return result; } @@ -134,14 +134,19 @@ void RenderDetailsMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOf paintInfo.context->setStrokeThickness(1.0f); paintInfo.context->setFillColor(color, style()->colorSpace()); + boxOrigin.move(borderLeft() + paddingLeft(), borderTop() + paddingTop()); paintInfo.context->fillPath(getPath(boxOrigin)); } bool RenderDetailsMarker::isOpen() const { for (RenderObject* renderer = parent(); renderer; renderer = renderer->parent()) { - if (renderer->node() && renderer->node()->hasTagName(detailsTag)) + if (!renderer->node()) + continue; + if (renderer->node()->hasTagName(detailsTag)) return !toElement(renderer->node())->getAttribute(openAttr).isNull(); + if (renderer->node()->hasTagName(inputTag)) + return true; } return false; diff --git a/Source/WebCore/rendering/RenderDetailsMarker.h b/Source/WebCore/rendering/RenderDetailsMarker.h index 3afac553b..76e2b28e4 100644 --- a/Source/WebCore/rendering/RenderDetailsMarker.h +++ b/Source/WebCore/rendering/RenderDetailsMarker.h @@ -21,7 +21,7 @@ #ifndef RenderDetailsMarker_h #define RenderDetailsMarker_h -#if ENABLE(DETAILS) +#if ENABLE(DETAILS) || ENABLE(CALENDAR_PICKER) #include "RenderBlock.h" @@ -42,7 +42,7 @@ private: bool isOpen() const; Path getCanonicalPath() const; - Path getPath(const IntPoint& origin) const; + Path getPath(const LayoutPoint& origin) const; }; inline RenderDetailsMarker* toRenderDetailsMarker(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderEmbeddedObject.cpp b/Source/WebCore/rendering/RenderEmbeddedObject.cpp index c239db277..2168a400a 100644 --- a/Source/WebCore/rendering/RenderEmbeddedObject.cpp +++ b/Source/WebCore/rendering/RenderEmbeddedObject.cpp @@ -53,10 +53,6 @@ #include "Text.h" #include "TextRun.h" -#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) -#include "HTMLVideoElement.h" -#endif - namespace WebCore { using namespace HTMLNames; @@ -83,10 +79,6 @@ 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() @@ -269,16 +261,17 @@ bool RenderEmbeddedObject::nodeAtPoint(const HitTestRequest& request, HitTestRes return true; PluginViewBase* view = static_cast<PluginViewBase*>(widget()); + IntPoint roundedPoint = roundedIntPoint(pointInContainer); if (Scrollbar* horizontalScrollbar = view->horizontalScrollbar()) { - if (horizontalScrollbar->shouldParticipateInHitTesting() && horizontalScrollbar->frameRect().contains(pointInContainer)) { + if (horizontalScrollbar->shouldParticipateInHitTesting() && horizontalScrollbar->frameRect().contains(roundedPoint)) { result.setScrollbar(horizontalScrollbar); return true; } } if (Scrollbar* verticalScrollbar = view->verticalScrollbar()) { - if (verticalScrollbar->shouldParticipateInHitTesting() && verticalScrollbar->frameRect().contains(pointInContainer)) { + if (verticalScrollbar->shouldParticipateInHitTesting() && verticalScrollbar->frameRect().contains(roundedPoint)) { result.setScrollbar(verticalScrollbar); return true; } diff --git a/Source/WebCore/rendering/RenderFieldset.cpp b/Source/WebCore/rendering/RenderFieldset.cpp index 3b70e6a11..8870a872f 100644 --- a/Source/WebCore/rendering/RenderFieldset.cpp +++ b/Source/WebCore/rendering/RenderFieldset.cpp @@ -132,11 +132,11 @@ void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint // cases the legend is embedded in the right and bottom borders respectively. // https://bugs.webkit.org/show_bug.cgi?id=47236 if (style()->isHorizontalWritingMode()) { - LayoutUnit yOff = (legend->y() > 0) ? zeroLayoutUnit : (legend->height() - borderTop()) / 2; + LayoutUnit yOff = (legend->y() > 0) ? ZERO_LAYOUT_UNIT : (legend->height() - borderTop()) / 2; paintRect.setHeight(paintRect.height() - yOff); paintRect.setY(paintRect.y() + yOff); } else { - LayoutUnit xOff = (legend->x() > 0) ? zeroLayoutUnit : (legend->width() - borderLeft()) / 2; + LayoutUnit xOff = (legend->x() > 0) ? ZERO_LAYOUT_UNIT : (legend->width() - borderLeft()) / 2; paintRect.setWidth(paintRect.width() - xOff); paintRect.setX(paintRect.x() + xOff); } @@ -159,11 +159,11 @@ void RenderFieldset::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint if (style()->isHorizontalWritingMode()) { LayoutUnit clipTop = paintRect.y(); LayoutUnit clipHeight = max(static_cast<LayoutUnit>(style()->borderTopWidth()), legend->height() - ((legend->height() - borderTop()) / 2)); - graphicsContext->clipOut(LayoutRect(paintRect.x() + legend->x(), clipTop, legend->width(), clipHeight)); + graphicsContext->clipOut(pixelSnappedIntRect(paintRect.x() + legend->x(), clipTop, legend->width(), clipHeight)); } else { LayoutUnit clipLeft = paintRect.x(); LayoutUnit clipWidth = max(static_cast<LayoutUnit>(style()->borderLeftWidth()), legend->width()); - graphicsContext->clipOut(LayoutRect(clipLeft, paintRect.y() + legend->y(), clipWidth, legend->height())); + graphicsContext->clipOut(pixelSnappedIntRect(clipLeft, paintRect.y() + legend->y(), clipWidth, legend->height())); } paintBorder(paintInfo, paintRect, style()); @@ -183,11 +183,11 @@ void RenderFieldset::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOff // cases the legend is embedded in the right and bottom borders respectively. // https://bugs.webkit.org/show_bug.cgi?id=47236 if (style()->isHorizontalWritingMode()) { - LayoutUnit yOff = (legend->y() > 0) ? 0 : (legend->height() - borderTop()) / 2; + LayoutUnit yOff = (legend->y() > 0) ? ZERO_LAYOUT_UNIT : (legend->height() - borderTop()) / 2; paintRect.expand(0, -yOff); paintRect.move(0, yOff); } else { - LayoutUnit xOff = (legend->x() > 0) ? 0 : (legend->width() - borderLeft()) / 2; + LayoutUnit xOff = (legend->x() > 0) ? ZERO_LAYOUT_UNIT : (legend->width() - borderLeft()) / 2; paintRect.expand(-xOff, 0); paintRect.move(xOff, 0); } @@ -195,4 +195,13 @@ void RenderFieldset::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOff paintMaskImages(paintInfo, paintRect); } +bool RenderFieldset::stretchesToMinIntrinsicLogicalWidth() const +{ + // If width is explicitly specified then Fieldsets should not stretch + if (style()->width().isPercent()) + return false; + + return true; +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderFieldset.h b/Source/WebCore/rendering/RenderFieldset.h index bd12c5553..12dbda502 100644 --- a/Source/WebCore/rendering/RenderFieldset.h +++ b/Source/WebCore/rendering/RenderFieldset.h @@ -42,7 +42,7 @@ private: virtual void computePreferredLogicalWidths(); virtual bool avoidsFloats() const { return true; } - virtual bool stretchesToMinIntrinsicLogicalWidth() const { return true; } + virtual bool stretchesToMinIntrinsicLogicalWidth() const OVERRIDE; virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&); virtual void paintMask(PaintInfo&, const LayoutPoint&); diff --git a/Source/WebCore/rendering/RenderFileUploadControl.cpp b/Source/WebCore/rendering/RenderFileUploadControl.cpp index 74e6f7de7..fd62630a8 100644 --- a/Source/WebCore/rendering/RenderFileUploadControl.cpp +++ b/Source/WebCore/rendering/RenderFileUploadControl.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "RenderFileUploadControl.h" +#include "ElementShadow.h" #include "FileList.h" #include "GraphicsContext.h" #include "HTMLInputElement.h" @@ -32,7 +33,6 @@ #include "RenderText.h" #include "RenderTheme.h" #include "ShadowRoot.h" -#include "ShadowTree.h" #include "TextRun.h" #include "VisiblePosition.h" #include <math.h> @@ -52,6 +52,7 @@ const int buttonShadowHeight = 2; RenderFileUploadControl::RenderFileUploadControl(HTMLInputElement* input) : RenderBlock(input) + , m_canReceiveDroppedFiles(input->canReceiveDroppedFiles()) { } @@ -72,8 +73,12 @@ void RenderFileUploadControl::updateFromElement() // updateFromElement() eventually. if (button->disabled() != newDisabled) button->setDisabled(newDisabled); - - button->setActive(input->canReceiveDroppedFiles()); + + bool newCanReceiveDroppedFilesState = input->canReceiveDroppedFiles(); + if (m_canReceiveDroppedFiles != newCanReceiveDroppedFilesState) { + m_canReceiveDroppedFiles = newCanReceiveDroppedFilesState; + button->setActive(newCanReceiveDroppedFilesState); + } } // This only supports clearing out the files, but that's OK because for @@ -86,13 +91,13 @@ void RenderFileUploadControl::updateFromElement() static int nodeWidth(Node* node) { - return node ? node->renderBox()->width() : zeroLayoutUnit; + return node ? node->renderBox()->pixelSnappedWidth() : 0; } int RenderFileUploadControl::maxFilenameWidth() const { HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); - return max(0, contentWidth() - nodeWidth(uploadButton()) - afterButtonSpacing + return max(0, contentBoxRect().pixelSnappedWidth() - nodeWidth(uploadButton()) - afterButtonSpacing - (input->icon() ? iconWidth + iconFilenameSpacing : 0)); } @@ -104,7 +109,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoin // Push a clip. GraphicsContextStateSaver stateSaver(*paintInfo.context, false); if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) { - LayoutRect clipRect(paintOffset.x() + borderLeft(), paintOffset.y() + borderTop(), + IntRect clipRect = pixelSnappedIntRect(paintOffset.x() + borderLeft(), paintOffset.y() + borderTop(), width() - borderLeft() - borderRight(), height() - borderBottom() - borderTop() + buttonShadowHeight); if (clipRect.isEmpty()) return; @@ -142,7 +147,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoin paintInfo.context->setFillColor(style()->visitedDependentColor(CSSPropertyColor), style()->colorSpace()); // Draw the filename - paintInfo.context->drawBidiText(font, textRun, LayoutPoint(textX, textY)); + paintInfo.context->drawBidiText(font, textRun, IntPoint(roundToInt(textX), roundToInt(textY))); if (input->icon()) { // Determine where the icon should be placed @@ -154,7 +159,7 @@ void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoin iconX = contentLeft + contentWidth() - buttonWidth - afterButtonSpacing - iconWidth; // Draw the file icon - input->icon()->paint(paintInfo.context, LayoutRect(iconX, iconY, iconWidth, iconHeight)); + input->icon()->paint(paintInfo.context, IntRect(roundToInt(iconX), roundToInt(iconY), iconWidth, iconHeight)); } } @@ -220,7 +225,7 @@ HTMLInputElement* RenderFileUploadControl::uploadButton() const ASSERT(input->hasShadowRoot()); - Node* buttonNode = input->shadowTree()->oldestShadowRoot()->firstChild(); + Node* buttonNode = input->shadow()->oldestShadowRoot()->firstChild(); return buttonNode && buttonNode->isHTMLElement() && buttonNode->hasTagName(inputTag) ? static_cast<HTMLInputElement*>(buttonNode) : 0; } @@ -236,7 +241,7 @@ String RenderFileUploadControl::fileTextValue() const { HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); ASSERT(input->files()); - return theme()->fileListNameForWidth(input->files()->paths(), style()->font(), maxFilenameWidth(), input->multiple()); + return theme()->fileListNameForWidth(input->files(), style()->font(), maxFilenameWidth(), input->multiple()); } } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderFileUploadControl.h b/Source/WebCore/rendering/RenderFileUploadControl.h index 11d959dac..11015eb90 100644 --- a/Source/WebCore/rendering/RenderFileUploadControl.h +++ b/Source/WebCore/rendering/RenderFileUploadControl.h @@ -55,6 +55,8 @@ private: virtual VisiblePosition positionForPoint(const LayoutPoint&); HTMLInputElement* uploadButton() const; + + bool m_canReceiveDroppedFiles; }; inline RenderFileUploadControl* toRenderFileUploadControl(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp index e9dd8381d..efa2eb71d 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.cpp +++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp @@ -102,38 +102,30 @@ private: Vector<int>::const_iterator m_orderValuesIterator; }; -struct RenderFlexibleBox::WrapReverseContext { - explicit WrapReverseContext(EFlexWrap flexWrap) - : isWrapReverse(flexWrap == FlexWrapReverse) +struct RenderFlexibleBox::LineContext { + LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent) + : crossAxisOffset(crossAxisOffset) + , crossAxisExtent(crossAxisExtent) + , numberOfChildren(numberOfChildren) + , maxAscent(maxAscent) { } - void addCrossAxisOffset(LayoutUnit offset) - { - if (!isWrapReverse) - return; - crossAxisOffsets.append(offset); - } - - void addNumberOfChildrenOnLine(size_t numberOfChildren) - { - if (!isWrapReverse) - return; - childrenPerLine.append(numberOfChildren); - } + LayoutUnit crossAxisOffset; + LayoutUnit crossAxisExtent; + size_t numberOfChildren; + LayoutUnit maxAscent; +}; - LayoutUnit lineCrossAxisDelta(size_t line, LayoutUnit crossAxisContentExtent) const +struct RenderFlexibleBox::Violation { + Violation(RenderBox* child, LayoutUnit childSize) + : child(child) + , childSize(childSize) { - ASSERT(line + 1 < crossAxisOffsets.size()); - LayoutUnit lineHeight = crossAxisOffsets[line + 1] - crossAxisOffsets[line]; - LayoutUnit originalOffset = crossAxisOffsets[line] - crossAxisOffsets[0]; - LayoutUnit newOffset = crossAxisContentExtent - originalOffset - lineHeight; - return newOffset - originalOffset; } - WTF::Vector<LayoutUnit> crossAxisOffsets; - WTF::Vector<size_t> childrenPerLine; - bool isWrapReverse; + RenderBox* child; + LayoutUnit childSize; }; @@ -188,11 +180,19 @@ void RenderFlexibleBox::computePreferredLogicalWidths() minPreferredLogicalWidth += margin; maxPreferredLogicalWidth += margin; if (!isColumnFlow()) { - m_minPreferredLogicalWidth += minPreferredLogicalWidth; m_maxPreferredLogicalWidth += maxPreferredLogicalWidth; + if (isMultiline()) { + // For multiline, the min preferred width is if you put a break between each item. + m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, minPreferredLogicalWidth); + } else + m_minPreferredLogicalWidth += minPreferredLogicalWidth; } else { m_minPreferredLogicalWidth = std::max(minPreferredLogicalWidth, m_minPreferredLogicalWidth); - m_maxPreferredLogicalWidth = std::max(maxPreferredLogicalWidth, m_maxPreferredLogicalWidth); + if (isMultiline()) { + // For multiline, the max preferred width is if you put a break between each item. + m_maxPreferredLogicalWidth += maxPreferredLogicalWidth; + } else + m_maxPreferredLogicalWidth = std::max(maxPreferredLogicalWidth, m_maxPreferredLogicalWidth); } } @@ -230,7 +230,7 @@ void RenderFlexibleBox::computePreferredLogicalWidths() setPreferredLogicalWidthsDirty(false); } -void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int, BlockLayoutPass) +void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit) { ASSERT(needsLayout()); @@ -247,12 +247,10 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int, BlockLayoutPass) } computeInitialRegionRangeForBlock(); - IntSize previousSize = size(); + LayoutSize previousSize = size(); setLogicalHeight(0); - // We need to call both of these because we grab both crossAxisExtent and mainAxisExtent in layoutFlexItems. computeLogicalWidth(); - computeLogicalHeight(); m_overflow.clear(); @@ -264,10 +262,15 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int, BlockLayoutPass) layer()->setHasVerticalScrollbar(true); } - layoutFlexItems(relayoutChildren); + WTF::Vector<LineContext> lineContexts; + FlexOrderHashSet flexOrderValues; + computeMainAxisPreferredSizes(relayoutChildren, flexOrderValues); + FlexOrderIterator flexIterator(this, flexOrderValues); + layoutFlexItems(flexIterator, lineContexts); LayoutUnit oldClientAfterEdge = clientLogicalBottom(); computeLogicalHeight(); + repositionLogicalHeightDependentFlexItems(flexIterator, lineContexts, oldClientAfterEdge); if (size() != previousSize) relayoutChildren = true; @@ -284,13 +287,35 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int, BlockLayoutPass) // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. - updateScrollInfoAfterLayout(); + if (hasOverflowClip()) + layer()->updateScrollInfoAfterLayout(); repainter.repaintAfterLayout(); setNeedsLayout(false); } +void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(FlexOrderIterator& iterator, WTF::Vector<LineContext>& lineContexts, LayoutUnit& oldClientAfterEdge) +{ + LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? ZERO_LAYOUT_UNIT : lineContexts[0].crossAxisOffset; + packFlexLines(iterator, lineContexts); + + // If we have a single line flexbox, the line height is all the available space. + // For flex-direction: row, this means we need to use the height, so we do this after calling computeLogicalHeight. + if (!isMultiline() && lineContexts.size() == 1) + lineContexts[0].crossAxisExtent = crossAxisContentExtent(); + alignChildren(iterator, lineContexts); + + if (style()->flexWrap() == FlexWrapReverse) { + if (isHorizontalFlow()) + oldClientAfterEdge = clientLogicalBottom(); + flipForWrapReverse(iterator, lineContexts, crossAxisStartEdge); + } + + // direction:rtl + flex-direction:column means the cross-axis direction is flipped. + flipForRightToLeftColumn(iterator); +} + bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const { // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow. @@ -321,9 +346,12 @@ bool RenderFlexibleBox::isMultiline() const return style()->flexWrap() != FlexWrapNone; } -Length RenderFlexibleBox::mainAxisLengthForChild(RenderBox* child) const +Length RenderFlexibleBox::preferredLengthForChild(RenderBox* child) const { - return isHorizontalFlow() ? child->style()->width() : child->style()->height(); + Length flexLength = child->style()->flexPreferredSize(); + if (flexLength.isAuto()) + flexLength = isHorizontalFlow() ? child->style()->width() : child->style()->height(); + return flexLength; } Length RenderFlexibleBox::crossAxisLength() const @@ -560,62 +588,58 @@ LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child) LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child) const { - Length mainAxisLength = mainAxisLengthForChild(child); + Length mainAxisLength = preferredLengthForChild(child); if (mainAxisLength.isAuto()) { LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth(); - return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) - mainAxisScrollbarExtentForChild(child); + return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child); } - return mainAxisLength.calcMinValue(mainAxisContentExtent()); + return minimumValueForLength(mainAxisLength, mainAxisContentExtent(), view()); } -void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren) +LayoutUnit RenderFlexibleBox::computeAvailableFreeSpace(LayoutUnit preferredMainAxisExtent) { - FlexOrderHashSet flexOrderValues; - computeMainAxisPreferredSizes(relayoutChildren, flexOrderValues); + LayoutUnit contentExtent = 0; + if (!isColumnFlow()) + contentExtent = mainAxisContentExtent(); + else if (hasOverrideHeight()) + contentExtent = overrideHeight() - (logicalHeight() - contentLogicalHeight()); + else { + LayoutUnit heightResult = computeContentLogicalHeightUsing(style()->logicalHeight()); + if (heightResult == -1) + heightResult = preferredMainAxisExtent; + LayoutUnit minHeight = computeContentLogicalHeightUsing(style()->logicalMinHeight()); // Leave as -1 if unset. + LayoutUnit maxHeight = style()->logicalMaxHeight().isUndefined() ? heightResult : computeContentLogicalHeightUsing(style()->logicalMaxHeight()); + if (maxHeight == -1) + maxHeight = heightResult; + heightResult = std::min(maxHeight, heightResult); + heightResult = std::max(minHeight, heightResult); + contentExtent = heightResult; + } + return contentExtent - preferredMainAxisExtent; +} + +void RenderFlexibleBox::layoutFlexItems(FlexOrderIterator& iterator, WTF::Vector<LineContext>& lineContexts) +{ OrderedFlexItemList orderedChildren; LayoutUnit preferredMainAxisExtent; float totalPositiveFlexibility; float totalNegativeFlexibility; - FlexOrderIterator flexIterator(this, flexOrderValues); - - // For wrap-reverse, we need to layout as wrap, then reverse the lines. The next two arrays - // are some extra information so it's possible to reverse the lines. - WrapReverseContext wrapReverseContext(style()->flexWrap()); + LayoutUnit minMaxAppliedMainAxisExtent; LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore(); - LayoutUnit mainAxisFlexibleSpace = mainAxisContentExtent(); - while (computeNextFlexLine(flexIterator, orderedChildren, preferredMainAxisExtent, totalPositiveFlexibility, totalNegativeFlexibility)) { - LayoutUnit availableFreeSpace = mainAxisFlexibleSpace - preferredMainAxisExtent; + while (computeNextFlexLine(iterator, orderedChildren, preferredMainAxisExtent, totalPositiveFlexibility, totalNegativeFlexibility, minMaxAppliedMainAxisExtent)) { + LayoutUnit availableFreeSpace = computeAvailableFreeSpace(preferredMainAxisExtent); + FlexSign flexSign = (minMaxAppliedMainAxisExtent < preferredMainAxisExtent + availableFreeSpace) ? PositiveFlexibility : NegativeFlexibility; InflexibleFlexItemSize inflexibleItems; WTF::Vector<LayoutUnit> childSizes; - while (!runFreeSpaceAllocationAlgorithm(orderedChildren, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems, childSizes)) { + while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems, childSizes)) { ASSERT(totalPositiveFlexibility >= 0 && totalNegativeFlexibility >= 0); ASSERT(inflexibleItems.size() > 0); } - wrapReverseContext.addNumberOfChildrenOnLine(orderedChildren.size()); - wrapReverseContext.addCrossAxisOffset(crossAxisOffset); - layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace); - } - - if (wrapReverseContext.isWrapReverse) { - wrapReverseContext.addCrossAxisOffset(crossAxisOffset); - flipForWrapReverse(flexIterator, wrapReverseContext); + layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, lineContexts); } - - // direction:rtl + flex-direction:column means the cross-axis direction is flipped. - flipForRightToLeftColumn(flexIterator); -} - -float RenderFlexibleBox::positiveFlexForChild(RenderBox* child) const -{ - return isHorizontalFlow() ? child->style()->flexboxWidthPositiveFlex() : child->style()->flexboxHeightPositiveFlex(); -} - -float RenderFlexibleBox::negativeFlexForChild(RenderBox* child) const -{ - return isHorizontalFlow() ? child->style()->flexboxWidthNegativeFlex() : child->style()->flexboxHeightNegativeFlex(); } LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child) @@ -635,6 +659,7 @@ LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child) void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, FlexOrderHashSet& flexOrderValues) { LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent(); + RenderView* renderView = view(); for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { flexOrderValues.add(child->style()->flexOrder()); @@ -642,7 +667,7 @@ void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, Fle continue; child->clearOverrideSize(); - if (mainAxisLengthForChild(child).isAuto()) { + if (preferredLengthForChild(child).isAuto()) { if (!relayoutChildren) child->setChildNeedsLayout(true); child->layoutIfNeeded(); @@ -652,52 +677,100 @@ void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, Fle // of 0 and because if we're not auto sizing, we don't do a layout that // computes the start/end margins. if (isHorizontalFlow()) { - child->setMarginLeft(child->style()->marginLeft().calcMinValue(flexboxAvailableContentExtent)); - child->setMarginRight(child->style()->marginRight().calcMinValue(flexboxAvailableContentExtent)); + child->setMarginLeft(minimumValueForLength(child->style()->marginLeft(), flexboxAvailableContentExtent, renderView)); + child->setMarginRight(minimumValueForLength(child->style()->marginRight(), flexboxAvailableContentExtent, renderView)); } else { - child->setMarginTop(child->style()->marginTop().calcMinValue(flexboxAvailableContentExtent)); - child->setMarginBottom(child->style()->marginBottom().calcMinValue(flexboxAvailableContentExtent)); + child->setMarginTop(minimumValueForLength(child->style()->marginTop(), flexboxAvailableContentExtent, renderView)); + child->setMarginBottom(minimumValueForLength(child->style()->marginBottom(), flexboxAvailableContentExtent, renderView)); } } } -bool RenderFlexibleBox::computeNextFlexLine(FlexOrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility) +LayoutUnit RenderFlexibleBox::lineBreakLength() +{ + if (!isColumnFlow()) + return mainAxisContentExtent(); + + LayoutUnit height = computeContentLogicalHeightUsing(style()->logicalHeight()); + if (height == -1) + height = MAX_LAYOUT_UNIT; + LayoutUnit maxHeight = computeContentLogicalHeightUsing(style()->logicalMaxHeight()); + if (maxHeight != -1) + height = std::min(height, maxHeight); + return height; +} + +LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize, LayoutUnit flexboxAvailableContentExtent) +{ + Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight(); + Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight(); + RenderView* renderView = view(); + // FIXME: valueForLength isn't quite right in quirks mode: percentage heights should check parents until a value is found. + // https://bugs.webkit.org/show_bug.cgi?id=81809 + if (max.isSpecified() && childSize > valueForLength(max, flexboxAvailableContentExtent, renderView)) + childSize = valueForLength(max, flexboxAvailableContentExtent, renderView); + if (min.isSpecified() && childSize < valueForLength(min, flexboxAvailableContentExtent, renderView)) + childSize = valueForLength(min, flexboxAvailableContentExtent, renderView); + return childSize; +} + +bool RenderFlexibleBox::computeNextFlexLine(FlexOrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility, LayoutUnit& minMaxAppliedMainAxisExtent) { orderedChildren.clear(); preferredMainAxisExtent = 0; totalPositiveFlexibility = totalNegativeFlexibility = 0; + minMaxAppliedMainAxisExtent = 0; if (!iterator.currentChild()) return false; + LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent(); + LayoutUnit lineBreak = lineBreakLength(); + for (RenderBox* child = iterator.currentChild(); child; child = iterator.next()) { if (child->isPositioned()) { orderedChildren.append(child); continue; } - LayoutUnit childMainAxisExtent = mainAxisBorderAndPaddingExtentForChild(child) + preferredMainAxisContentExtentForChild(child); - if (isHorizontalFlow()) - childMainAxisExtent += child->marginWidth(); - else - childMainAxisExtent += child->marginHeight(); + LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child); + LayoutUnit childMainAxisMarginBoxExtent = mainAxisBorderAndPaddingExtentForChild(child) + childMainAxisExtent; + childMainAxisMarginBoxExtent += isHorizontalFlow() ? child->marginWidth() : child->marginHeight(); - if (isMultiline() && preferredMainAxisExtent + childMainAxisExtent > mainAxisContentExtent() && orderedChildren.size() > 0) + if (isMultiline() && preferredMainAxisExtent + childMainAxisMarginBoxExtent > lineBreak && orderedChildren.size() > 0) break; orderedChildren.append(child); - preferredMainAxisExtent += childMainAxisExtent; - totalPositiveFlexibility += positiveFlexForChild(child); - totalNegativeFlexibility += negativeFlexForChild(child); + preferredMainAxisExtent += childMainAxisMarginBoxExtent; + totalPositiveFlexibility += child->style()->positiveFlex(); + totalNegativeFlexibility += child->style()->negativeFlex(); + + LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent, flexboxAvailableContentExtent); + minMaxAppliedMainAxisExtent += childMinMaxAppliedMainAxisExtent - childMainAxisExtent + childMainAxisMarginBoxExtent; } return true; } +void RenderFlexibleBox::freezeViolations(const WTF::Vector<Violation>& violations, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems) +{ + for (size_t i = 0; i < violations.size(); ++i) { + RenderBox* child = violations[i].child; + LayoutUnit childSize = violations[i].childSize; + availableFreeSpace -= childSize - preferredMainAxisContentExtentForChild(child); + totalPositiveFlexibility -= child->style()->positiveFlex(); + totalNegativeFlexibility -= child->style()->negativeFlex(); + inflexibleItems.set(child, childSize); + } +} + // Returns true if we successfully ran the algorithm and sized the flex items. -bool RenderFlexibleBox::runFreeSpaceAllocationAlgorithm(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes) +bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes) { childSizes.clear(); - LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent(); + LayoutUnit totalViolation = 0; + LayoutUnit usedFreeSpace = 0; + WTF::Vector<Violation> minViolations; + WTF::Vector<Violation> maxViolations; for (size_t i = 0; i < children.size(); ++i) { RenderBox* child = children[i]; if (child->isPositioned()) { @@ -705,59 +778,53 @@ bool RenderFlexibleBox::runFreeSpaceAllocationAlgorithm(const OrderedFlexItemLis continue; } - LayoutUnit childPreferredSize; if (inflexibleItems.contains(child)) - childPreferredSize = inflexibleItems.get(child); + childSizes.append(inflexibleItems.get(child)); else { - childPreferredSize = preferredMainAxisContentExtentForChild(child); - if (availableFreeSpace > 0 && totalPositiveFlexibility > 0) { - childPreferredSize += lroundf(availableFreeSpace * positiveFlexForChild(child) / totalPositiveFlexibility); - - Length childLogicalMaxWidth = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight(); - if (!childLogicalMaxWidth.isUndefined() && childLogicalMaxWidth.isSpecified() && childPreferredSize > childLogicalMaxWidth.calcValue(flexboxAvailableContentExtent)) { - childPreferredSize = childLogicalMaxWidth.calcValue(flexboxAvailableContentExtent); - availableFreeSpace -= childPreferredSize - preferredMainAxisContentExtentForChild(child); - totalPositiveFlexibility -= positiveFlexForChild(child); - - inflexibleItems.set(child, childPreferredSize); - return false; - } - } else if (availableFreeSpace < 0 && totalNegativeFlexibility > 0) { - childPreferredSize += lroundf(availableFreeSpace * negativeFlexForChild(child) / totalNegativeFlexibility); - - Length childLogicalMinWidth = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight(); - if (!childLogicalMinWidth.isUndefined() && childLogicalMinWidth.isSpecified() && childPreferredSize < childLogicalMinWidth.calcValue(flexboxAvailableContentExtent)) { - childPreferredSize = childLogicalMinWidth.calcValue(flexboxAvailableContentExtent); - availableFreeSpace += preferredMainAxisContentExtentForChild(child) - childPreferredSize; - totalNegativeFlexibility -= negativeFlexForChild(child); - - inflexibleItems.set(child, childPreferredSize); - return false; - } - } + LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child); + LayoutUnit childSize = preferredChildSize; + if (availableFreeSpace > 0 && totalPositiveFlexibility > 0 && flexSign == PositiveFlexibility) + childSize += lroundf(availableFreeSpace * child->style()->positiveFlex() / totalPositiveFlexibility); + else if (availableFreeSpace < 0 && totalNegativeFlexibility > 0 && flexSign == NegativeFlexibility) + childSize += lroundf(availableFreeSpace * child->style()->negativeFlex() / totalNegativeFlexibility); + + LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize, flexboxAvailableContentExtent); + childSizes.append(adjustedChildSize); + usedFreeSpace += adjustedChildSize - preferredChildSize; + + LayoutUnit violation = adjustedChildSize - childSize; + if (violation > 0) + minViolations.append(Violation(child, adjustedChildSize)); + else if (violation < 0) + maxViolations.append(Violation(child, adjustedChildSize)); + totalViolation += violation; } - childSizes.append(childPreferredSize); } - return true; + + if (totalViolation) + freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems); + else + availableFreeSpace -= usedFreeSpace; + + return !totalViolation; } -static LayoutUnit initialPackingOffset(LayoutUnit availableFreeSpace, EFlexPack flexPack, size_t numberOfChildren) +static LayoutUnit initialPackingOffset(LayoutUnit availableFreeSpace, EFlexPack flexPack, unsigned numberOfChildren) { - if (availableFreeSpace > 0) { - if (flexPack == PackEnd) - return availableFreeSpace; - if (flexPack == PackCenter) - return availableFreeSpace / 2; - if (flexPack == PackDistribute && numberOfChildren) + if (flexPack == PackEnd) + return availableFreeSpace; + if (flexPack == PackCenter) + return availableFreeSpace / 2; + if (flexPack == PackDistribute) { + if (availableFreeSpace > 0 && numberOfChildren) return availableFreeSpace / (2 * numberOfChildren); - } else if (availableFreeSpace < 0) { - if (flexPack == PackCenter || flexPack == PackDistribute) + if (availableFreeSpace < 0) return availableFreeSpace / 2; } return 0; } -static LayoutUnit packingSpaceBetweenChildren(LayoutUnit availableFreeSpace, EFlexPack flexPack, size_t numberOfChildren) +static LayoutUnit packingSpaceBetweenChildren(LayoutUnit availableFreeSpace, EFlexPack flexPack, unsigned numberOfChildren) { if (availableFreeSpace > 0 && numberOfChildren > 1) { if (flexPack == PackJustify) @@ -791,7 +858,7 @@ void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, Layout if (childLayer->staticBlockPosition() != staticBlockPosition) { childLayer->setStaticBlockPosition(staticBlockPosition); if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) - child->setChildNeedsLayout(true, false); + child->setChildNeedsLayout(true, MarkOnlyThis); } } @@ -811,8 +878,9 @@ static EFlexAlign flexAlignForChild(RenderBox* child) return align; } -void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace) +void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, WTF::Vector<LineContext>& lineContexts) { + ASSERT(childSizes.size() == children.size()); LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart(); mainAxisOffset += initialPackingOffset(availableFreeSpace, style()->flexPack(), childSizes.size()); if (style()->flexDirection() == FlowRowReverse) @@ -845,8 +913,8 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons childCrossAxisMarginBoxExtent = maxAscent + maxDescent; } else childCrossAxisMarginBoxExtent = crossAxisExtentForChild(child) + crossAxisMarginExtentForChild(child); - if (crossAxisLength().isAuto()) - setCrossAxisExtent(std::max(crossAxisExtent(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent())); + if (!isColumnFlow() && style()->logicalHeight().isAuto()) + setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent())); maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent); mainAxisOffset += flowAwareMarginStartForChild(child); @@ -872,10 +940,8 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons layoutColumnReverse(children, childSizes, crossAxisOffset, availableFreeSpace); } - LayoutUnit lineCrossAxisExtent = isMultiline() ? maxChildCrossAxisExtent : crossAxisContentExtent(); - alignChildren(children, lineCrossAxisExtent, maxAscent); - - crossAxisOffset += lineCrossAxisExtent; + lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent)); + crossAxisOffset += maxChildCrossAxisExtent; } void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace) @@ -906,6 +972,55 @@ void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, } } +static LayoutUnit initialLinePackingOffset(LayoutUnit availableFreeSpace, EFlexLinePack linePack, unsigned numberOfLines) +{ + if (linePack == LinePackEnd) + return availableFreeSpace; + if (linePack == LinePackCenter) + return availableFreeSpace / 2; + if (linePack == LinePackDistribute) { + if (availableFreeSpace > 0 && numberOfLines) + return availableFreeSpace / (2 * numberOfLines); + if (availableFreeSpace < 0) + return availableFreeSpace / 2; + } + return 0; +} + +static LayoutUnit linePackingSpaceBetweenChildren(LayoutUnit availableFreeSpace, EFlexLinePack linePack, unsigned numberOfLines) +{ + if (availableFreeSpace > 0 && numberOfLines > 1) { + if (linePack == LinePackJustify) + return availableFreeSpace / (numberOfLines - 1); + if (linePack == LinePackDistribute || linePack == LinePackStretch) + return availableFreeSpace / numberOfLines; + } + return 0; +} + +void RenderFlexibleBox::packFlexLines(FlexOrderIterator& iterator, WTF::Vector<LineContext>& lineContexts) +{ + if (!isMultiline() || style()->flexLinePack() == LinePackStart) + return; + + LayoutUnit availableCrossAxisSpace = crossAxisContentExtent(); + for (size_t i = 0; i < lineContexts.size(); ++i) + availableCrossAxisSpace -= lineContexts[i].crossAxisExtent; + + RenderBox* child = iterator.first(); + LayoutUnit lineOffset = initialLinePackingOffset(availableCrossAxisSpace, style()->flexLinePack(), lineContexts.size()); + for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) { + lineContexts[lineNumber].crossAxisOffset += lineOffset; + for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) + adjustAlignmentForChild(child, lineOffset); + + if (style()->flexLinePack() == LinePackStretch && availableCrossAxisSpace > 0) + lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size()); + + lineOffset += linePackingSpaceBetweenChildren(availableCrossAxisSpace, style()->flexLinePack(), lineContexts.size()); + } +} + void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta) { LayoutRect oldRect = child->frameRect(); @@ -919,72 +1034,94 @@ void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit del child->repaintDuringLayoutIfMoved(oldRect); } -void RenderFlexibleBox::alignChildren(const OrderedFlexItemList& children, LayoutUnit lineCrossAxisExtent, LayoutUnit maxAscent) +void RenderFlexibleBox::alignChildren(FlexOrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts) { - LayoutUnit minMarginAfterBaseline = std::numeric_limits<LayoutUnit>::max(); - - for (size_t i = 0; i < children.size(); ++i) { - RenderBox* child = children[i]; - switch (flexAlignForChild(child)) { - case AlignAuto: - ASSERT_NOT_REACHED(); - break; - case AlignStretch: { - if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) { - LayoutUnit logicalHeightBefore = child->logicalHeight(); - LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child); - child->setLogicalHeight(stretchedLogicalHeight); - child->computeLogicalHeight(); - - if (child->logicalHeight() != logicalHeightBefore) { - child->setOverrideHeight(child->logicalHeight()); - child->setLogicalHeight(0); - child->setChildNeedsLayout(true); - child->layoutIfNeeded(); - } - } else if (isColumnFlow() && child->style()->logicalWidth().isAuto() && isMultiline()) { - // FIXME: Handle min-width and max-width. - LayoutUnit childWidth = lineCrossAxisExtent - crossAxisMarginExtentForChild(child); - child->setOverrideWidth(std::max(0, childWidth)); - child->setChildNeedsLayout(true); - child->layoutIfNeeded(); + // Keep track of the space between the baseline edge and the after edge of the box for each line. + WTF::Vector<LayoutUnit> minMarginAfterBaselines; + + RenderBox* child = iterator.first(); + for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) { + LayoutUnit minMarginAfterBaseline = MAX_LAYOUT_UNIT; + LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent; + LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent; + + for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) { + ASSERT(child); + switch (flexAlignForChild(child)) { + case AlignAuto: + ASSERT_NOT_REACHED(); + break; + case AlignStretch: { + applyStretchAlignmentToChild(child, lineCrossAxisExtent); + // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end. + if (style()->flexWrap() == FlexWrapReverse) + adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child)); + break; } - // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end. - if (style()->flexWrap() == FlexWrapReverse) + case AlignStart: + break; + case AlignEnd: adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child)); - break; - } - case AlignStart: - break; - case AlignEnd: - adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child)); - break; - case AlignCenter: - adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2); - break; - case AlignBaseline: { - LayoutUnit ascent = marginBoxAscentForChild(child); - LayoutUnit startOffset = maxAscent - ascent; - adjustAlignmentForChild(child, startOffset); - - if (style()->flexWrap() == FlexWrapReverse) - minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset); - break; - } + break; + case AlignCenter: + adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2); + break; + case AlignBaseline: { + LayoutUnit ascent = marginBoxAscentForChild(child); + LayoutUnit startOffset = maxAscent - ascent; + adjustAlignmentForChild(child, startOffset); + + if (style()->flexWrap() == FlexWrapReverse) + minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset); + break; + } + } } + minMarginAfterBaselines.append(minMarginAfterBaseline); } + if (style()->flexWrap() != FlexWrapReverse) + return; + // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we // need to align the after edge of baseline elements with the after edge of the flex line. - if (style()->flexWrap() == FlexWrapReverse && minMarginAfterBaseline) { - for (size_t i = 0; i < children.size(); ++i) { - RenderBox* child = children[i]; - if (flexAlignForChild(child) == AlignBaseline) + child = iterator.first(); + for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) { + LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber]; + for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) { + ASSERT(child); + if (flexAlignForChild(child) == AlignBaseline && minMarginAfterBaseline) adjustAlignmentForChild(child, minMarginAfterBaseline); } } } +void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUnit lineCrossAxisExtent) +{ + if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) { + LayoutUnit logicalHeightBefore = child->logicalHeight(); + LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child); + if (stretchedLogicalHeight < logicalHeightBefore) + return; + + child->setLogicalHeight(stretchedLogicalHeight); + child->computeLogicalHeight(); + + if (child->logicalHeight() != logicalHeightBefore) { + child->setOverrideHeight(child->logicalHeight()); + child->setLogicalHeight(0); + child->setChildNeedsLayout(true); + child->layoutIfNeeded(); + } + } else if (isColumnFlow() && child->style()->logicalWidth().isAuto() && isMultiline()) { + // FIXME: Handle min-width and max-width. + LayoutUnit childWidth = lineCrossAxisExtent - crossAxisMarginExtentForChild(child); + child->setOverrideWidth(std::max(ZERO_LAYOUT_UNIT, childWidth)); + child->setChildNeedsLayout(true); + child->layoutIfNeeded(); + } +} + void RenderFlexibleBox::flipForRightToLeftColumn(FlexOrderIterator& iterator) { if (style()->isLeftToRightDirection() || !isColumnFlow()) @@ -998,26 +1135,23 @@ void RenderFlexibleBox::flipForRightToLeftColumn(FlexOrderIterator& iterator) } } -void RenderFlexibleBox::flipForWrapReverse(FlexOrderIterator& iterator, const WrapReverseContext& wrapReverseContext) +void RenderFlexibleBox::flipForWrapReverse(FlexOrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge) { - if (!isColumnFlow()) - computeLogicalHeight(); - - size_t currentChild = 0; - size_t lineNumber = 0; LayoutUnit contentExtent = crossAxisContentExtent(); - for (RenderBox* child = iterator.first(); child; child = iterator.next()) { - LayoutPoint location = flowAwareLocationForChild(child); - location.setY(location.y() + wrapReverseContext.lineCrossAxisDelta(lineNumber, contentExtent)); - - LayoutRect oldRect = child->frameRect(); - setFlowAwareLocationForChild(child, location); - if (!selfNeedsLayout() && child->checkForRepaintDuringLayout()) - child->repaintDuringLayoutIfMoved(oldRect); - - if (++currentChild == wrapReverseContext.childrenPerLine[lineNumber]) { - ++lineNumber; - currentChild = 0; + RenderBox* child = iterator.first(); + for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) { + for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) { + ASSERT(child); + LayoutPoint location = flowAwareLocationForChild(child); + LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent; + LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge; + LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent; + location.setY(location.y() + newOffset - originalOffset); + + LayoutRect oldRect = child->frameRect(); + setFlowAwareLocationForChild(child, location); + if (!selfNeedsLayout() && child->checkForRepaintDuringLayout()) + child->repaintDuringLayoutIfMoved(oldRect); } } } diff --git a/Source/WebCore/rendering/RenderFlexibleBox.h b/Source/WebCore/rendering/RenderFlexibleBox.h index 3490bf1c6..6c21b0494 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.h +++ b/Source/WebCore/rendering/RenderFlexibleBox.h @@ -44,11 +44,16 @@ public: virtual bool isFlexibleBox() const { return true; } virtual void computePreferredLogicalWidths(); - virtual void layoutBlock(bool relayoutChildren, int pageLogicalHeight = 0, BlockLayoutPass = NormalLayoutPass); + virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0); bool isHorizontalFlow() const; private: + enum FlexSign { + PositiveFlexibility, + NegativeFlexibility, + }; + struct FlexOrderHashTraits; typedef HashSet<int, DefaultHash<int>::Hash, FlexOrderHashTraits> FlexOrderHashSet; @@ -56,14 +61,15 @@ private: typedef WTF::HashMap<const RenderBox*, LayoutUnit> InflexibleFlexItemSize; typedef WTF::Vector<RenderBox*> OrderedFlexItemList; - struct WrapReverseContext; + struct LineContext; + struct Violation; bool hasOrthogonalFlow(RenderBox* child) const; bool isColumnFlow() const; bool isLeftToRightFlow() const; bool isMultiline() const; Length crossAxisLength() const; - Length mainAxisLengthForChild(RenderBox* child) const; + Length preferredLengthForChild(RenderBox* child) const; void setCrossAxisExtent(LayoutUnit); LayoutUnit crossAxisExtentForChild(RenderBox* child); LayoutUnit mainAxisExtentForChild(RenderBox* child); @@ -94,24 +100,30 @@ private: LayoutUnit mainAxisScrollbarExtentForChild(RenderBox* child) const; LayoutUnit preferredMainAxisContentExtentForChild(RenderBox* child) const; - void layoutFlexItems(bool relayoutChildren); - - float positiveFlexForChild(RenderBox* child) const; - float negativeFlexForChild(RenderBox* child) const; + void layoutFlexItems(FlexOrderIterator&, WTF::Vector<LineContext>&); + void repositionLogicalHeightDependentFlexItems(FlexOrderIterator&, WTF::Vector<LineContext>&, LayoutUnit& oldClientAfterEdge); LayoutUnit availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox*); LayoutUnit marginBoxAscentForChild(RenderBox*); void computeMainAxisPreferredSizes(bool relayoutChildren, FlexOrderHashSet&); - bool computeNextFlexLine(FlexOrderIterator&, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility); - bool runFreeSpaceAllocationAlgorithm(const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize&, WTF::Vector<LayoutUnit>& childSizes); + LayoutUnit lineBreakLength(); + LayoutUnit adjustChildSizeForMinAndMax(RenderBox*, LayoutUnit childSize, LayoutUnit flexboxAvailableContentExtent); + bool computeNextFlexLine(FlexOrderIterator&, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility, LayoutUnit& minMaxAppliedMainAxisExtent); + LayoutUnit computeAvailableFreeSpace(LayoutUnit preferredMainAxisExtent); + + bool resolveFlexibleLengths(FlexSign, const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize&, WTF::Vector<LayoutUnit>& childSizes); + void freezeViolations(const WTF::Vector<Violation>&, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize&); + void setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize); void prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset); - void layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList&, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace); + void layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList&, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, WTF::Vector<LineContext>&); void layoutColumnReverse(const OrderedFlexItemList&, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace); - void alignChildren(const OrderedFlexItemList&, LayoutUnit lineCrossAxisExtent, LayoutUnit maxAscent); + void packFlexLines(FlexOrderIterator&, WTF::Vector<LineContext>&); + void alignChildren(FlexOrderIterator&, const WTF::Vector<LineContext>&); + void applyStretchAlignmentToChild(RenderBox*, LayoutUnit lineCrossAxisExtent); void flipForRightToLeftColumn(FlexOrderIterator&); - void flipForWrapReverse(FlexOrderIterator&, const WrapReverseContext&); + void flipForWrapReverse(FlexOrderIterator&, const WTF::Vector<LineContext>&, LayoutUnit crossAxisStartEdge); }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderFlowThread.cpp b/Source/WebCore/rendering/RenderFlowThread.cpp index e241d9670..393964ade 100644 --- a/Source/WebCore/rendering/RenderFlowThread.cpp +++ b/Source/WebCore/rendering/RenderFlowThread.cpp @@ -31,6 +31,7 @@ #include "RenderFlowThread.h" +#include "FlowThreadController.h" #include "HitTestRequest.h" #include "HitTestResult.h" #include "Node.h" @@ -44,14 +45,14 @@ namespace WebCore { -RenderFlowThread::RenderFlowThread(Node* node, const AtomicString& flowThread) +RenderFlowThread::RenderFlowThread(Node* node) : RenderBlock(node) - , m_flowThread(flowThread) , m_hasValidRegions(false) , m_regionsInvalidated(false) , m_regionsHaveUniformLogicalWidth(true) , m_regionsHaveUniformLogicalHeight(true) , m_overflow(false) + , m_regionLayoutUpdateEventTimer(this, &RenderFlowThread::regionLayoutUpdateEventTimerFired) { ASSERT(node->document()->cssRegionsEnabled()); setIsAnonymous(false); @@ -82,63 +83,6 @@ void RenderFlowThread::styleDidChange(StyleDifference diff, const RenderStyle* o m_regionsInvalidated = true; } -RenderObject* RenderFlowThread::nextRendererForNode(Node* node) const -{ - FlowThreadChildList::const_iterator it = m_flowThreadChildList.begin(); - FlowThreadChildList::const_iterator end = m_flowThreadChildList.end(); - - for (; it != end; ++it) { - RenderObject* child = *it; - ASSERT(child->node()); - unsigned short position = node->compareDocumentPosition(child->node()); - if (position & Node::DOCUMENT_POSITION_FOLLOWING) - return child; - } - - return 0; -} - -RenderObject* RenderFlowThread::previousRendererForNode(Node* node) const -{ - if (m_flowThreadChildList.isEmpty()) - return 0; - - FlowThreadChildList::const_iterator begin = m_flowThreadChildList.begin(); - FlowThreadChildList::const_iterator end = m_flowThreadChildList.end(); - FlowThreadChildList::const_iterator it = end; - - do { - --it; - RenderObject* child = *it; - ASSERT(child->node()); - unsigned short position = node->compareDocumentPosition(child->node()); - if (position & Node::DOCUMENT_POSITION_PRECEDING) - return child; - } while (it != begin); - - return 0; -} - -void RenderFlowThread::addFlowChild(RenderObject* newChild, RenderObject* beforeChild) -{ - // The child list is used to sort the flow thread's children render objects - // based on their corresponding nodes DOM order. The list is needed to avoid searching the whole DOM. - - // Do not add anonymous objects. - if (!newChild->node()) - return; - - if (beforeChild) - m_flowThreadChildList.insertBefore(beforeChild, newChild); - else - m_flowThreadChildList.add(newChild); -} - -void RenderFlowThread::removeFlowChild(RenderObject* child) -{ - m_flowThreadChildList.remove(child); -} - void RenderFlowThread::removeFlowChildInfo(RenderObject* child) { if (child->isBox()) { @@ -148,149 +92,22 @@ void RenderFlowThread::removeFlowChildInfo(RenderObject* child) } } -// Compare two regions to determine in which one the content should flow first. -// The function returns true if the first passed region is "less" than the second passed region. -// If the first region appears before second region in DOM, -// the first region is "less" than the second region. -// If the first region is "less" than the second region, the first region receives content before second region. -static bool compareRenderRegions(const RenderRegion* firstRegion, const RenderRegion* secondRegion) -{ - ASSERT(firstRegion); - ASSERT(secondRegion); - - // If the regions have the same region-index, compare their position in dom. - ASSERT(firstRegion->node()); - ASSERT(secondRegion->node()); - - unsigned short position = firstRegion->node()->compareDocumentPosition(secondRegion->node()); - return (position & Node::DOCUMENT_POSITION_FOLLOWING); -} - -bool RenderFlowThread::dependsOn(RenderFlowThread* otherRenderFlowThread) const -{ - if (m_layoutBeforeThreadsSet.contains(otherRenderFlowThread)) - return true; - - // Recursively traverse the m_layoutBeforeThreadsSet. - RenderFlowThreadCountedSet::const_iterator iterator = m_layoutBeforeThreadsSet.begin(); - RenderFlowThreadCountedSet::const_iterator end = m_layoutBeforeThreadsSet.end(); - for (; iterator != end; ++iterator) { - const RenderFlowThread* beforeFlowThread = (*iterator).first; - if (beforeFlowThread->dependsOn(otherRenderFlowThread)) - return true; - } - - return false; -} - void RenderFlowThread::addRegionToThread(RenderRegion* renderRegion) { ASSERT(renderRegion); - if (m_regionList.isEmpty()) - m_regionList.add(renderRegion); - else { - // Find the first region "greater" than renderRegion. - RenderRegionList::iterator it = m_regionList.begin(); - while (it != m_regionList.end() && !compareRenderRegions(renderRegion, *it)) - ++it; - m_regionList.insertBefore(it, renderRegion); - } - - ASSERT(!renderRegion->isValid()); - if (renderRegion->parentFlowThread()) { - if (renderRegion->parentFlowThread()->dependsOn(this)) { - // Register ourself to get a notification when the state changes. - renderRegion->parentFlowThread()->m_observerThreadsSet.add(this); - return; - } - - addDependencyOnFlowThread(renderRegion->parentFlowThread()); - } - + m_regionList.add(renderRegion); renderRegion->setIsValid(true); - invalidateRegions(); } void RenderFlowThread::removeRegionFromThread(RenderRegion* renderRegion) { ASSERT(renderRegion); - m_regionRangeMap.clear(); m_regionList.remove(renderRegion); - - if (renderRegion->parentFlowThread()) { - if (!renderRegion->isValid()) { - renderRegion->parentFlowThread()->m_observerThreadsSet.remove(this); - // No need to invalidate the regions rectangles. The removed region - // was not taken into account. Just return here. - return; - } - removeDependencyOnFlowThread(renderRegion->parentFlowThread()); - } - invalidateRegions(); } -void RenderFlowThread::checkInvalidRegions() -{ - for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - // The only reason a region would be invalid is because it has a parent flow thread. - ASSERT(region->isValid() || region->parentFlowThread()); - if (region->isValid() || region->parentFlowThread()->dependsOn(this)) - continue; - - region->parentFlowThread()->m_observerThreadsSet.remove(this); - addDependencyOnFlowThread(region->parentFlowThread()); - region->setIsValid(true); - invalidateRegions(); - } - - if (m_observerThreadsSet.isEmpty()) - return; - - // Notify all the flow threads that were dependent on this flow. - - // Create a copy of the list first. That's because observers might change the list when calling checkInvalidRegions. - Vector<RenderFlowThread*> observers; - copyToVector(m_observerThreadsSet, observers); - - for (size_t i = 0; i < observers.size(); ++i) { - RenderFlowThread* flowThread = observers.at(i); - flowThread->checkInvalidRegions(); - } -} - -void RenderFlowThread::addDependencyOnFlowThread(RenderFlowThread* otherFlowThread) -{ - std::pair<RenderFlowThreadCountedSet::iterator, bool> result = m_layoutBeforeThreadsSet.add(otherFlowThread); - if (result.second) { - // This is the first time we see this dependency. Make sure we recalculate all the dependencies. - view()->setIsRenderFlowThreadOrderDirty(true); - } -} - -void RenderFlowThread::removeDependencyOnFlowThread(RenderFlowThread* otherFlowThread) -{ - bool removed = m_layoutBeforeThreadsSet.remove(otherFlowThread); - if (removed) { - checkInvalidRegions(); - view()->setIsRenderFlowThreadOrderDirty(true); - } -} - -void RenderFlowThread::pushDependencies(RenderFlowThreadList& list) -{ - for (RenderFlowThreadCountedSet::iterator iter = m_layoutBeforeThreadsSet.begin(); iter != m_layoutBeforeThreadsSet.end(); ++iter) { - RenderFlowThread* flowThread = (*iter).first; - if (list.contains(flowThread)) - continue; - flowThread->pushDependencies(list); - list.add(flowThread); - } -} - class CurrentRenderFlowThreadMaintainer { WTF_MAKE_NONCOPYABLE(CurrentRenderFlowThreadMaintainer); public: @@ -298,14 +115,14 @@ public: : m_renderFlowThread(renderFlowThread) { RenderView* view = m_renderFlowThread->view(); - ASSERT(!view->currentRenderFlowThread()); - view->setCurrentRenderFlowThread(m_renderFlowThread); + ASSERT(!view->flowThreadController()->currentRenderFlowThread()); + view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread); } ~CurrentRenderFlowThreadMaintainer() { RenderView* view = m_renderFlowThread->view(); - ASSERT(view->currentRenderFlowThread() == m_renderFlowThread); - view->setCurrentRenderFlowThread(0); + ASSERT(view->flowThreadController()->currentRenderFlowThread() == m_renderFlowThread); + view->flowThreadController()->setCurrentRenderFlowThread(0); } private: RenderFlowThread* m_renderFlowThread; @@ -318,14 +135,14 @@ public: : m_view(view) , m_renderFlowThread(0) { - m_renderFlowThread = m_view->currentRenderFlowThread(); + m_renderFlowThread = m_view->flowThreadController()->currentRenderFlowThread(); if (m_renderFlowThread) - view->setCurrentRenderFlowThread(0); + view->flowThreadController()->setCurrentRenderFlowThread(0); } ~CurrentRenderFlowThreadDisabler() { if (m_renderFlowThread) - m_view->setCurrentRenderFlowThread(m_renderFlowThread); + m_view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread); } private: RenderView* m_view; @@ -384,10 +201,10 @@ void RenderFlowThread::layout() continue; LayoutRect regionRect; if (isHorizontalWritingMode()) { - regionRect = LayoutRect(style()->direction() == LTR ? zeroLayoutUnit : logicalWidth() - region->contentWidth(), logicalHeight, region->contentWidth(), region->contentHeight()); + regionRect = LayoutRect(style()->direction() == LTR ? ZERO_LAYOUT_UNIT : logicalWidth() - region->contentWidth(), logicalHeight, region->contentWidth(), region->contentHeight()); logicalHeight += regionRect.height(); } else { - regionRect = LayoutRect(logicalHeight, style()->direction() == LTR ? zeroLayoutUnit : logicalWidth() - region->contentHeight(), region->contentWidth(), region->contentHeight()); + regionRect = LayoutRect(logicalHeight, style()->direction() == LTR ? ZERO_LAYOUT_UNIT : logicalWidth() - region->contentHeight(), region->contentWidth(), region->contentHeight()); logicalHeight += regionRect.width(); } region->setRegionRect(regionRect); @@ -399,6 +216,15 @@ void RenderFlowThread::layout() LayoutStateMaintainer statePusher(view(), this, regionsChanged); RenderBlock::layout(); statePusher.pop(); + if (document()->hasListenerType(Document::REGIONLAYOUTUPDATE_LISTENER) && !m_regionLayoutUpdateEventTimer.isActive()) + for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { + RenderRegion* region = *iter; + if (region->shouldDispatchRegionLayoutUpdateEvent()) { + // at least one region needs to dispatch the event + m_regionLayoutUpdateEventTimer.startOneShot(0); + break; + } + } } void RenderFlowThread::computeLogicalWidth() @@ -421,7 +247,7 @@ void RenderFlowThread::computeLogicalWidth() LayoutUnit regionLogicalWidth = isHorizontalWritingMode() ? region->contentWidth() : region->contentHeight(); if (regionLogicalWidth != logicalWidth) { - LayoutUnit logicalLeft = style()->direction() == LTR ? zeroLayoutUnit : logicalWidth - regionLogicalWidth; + LayoutUnit logicalLeft = style()->direction() == LTR ? ZERO_LAYOUT_UNIT : logicalWidth - regionLogicalWidth; region->setRenderBoxRegionInfo(this, logicalLeft, regionLogicalWidth, false); } } @@ -429,7 +255,7 @@ void RenderFlowThread::computeLogicalWidth() void RenderFlowThread::computeLogicalHeight() { - int logicalHeight = 0; + LayoutUnit logicalHeight = 0; for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; @@ -676,7 +502,7 @@ void RenderFlowThread::removeRenderBoxRegionInfo(RenderBox* box) } #ifndef NDEBUG - // We have to make sure we did not left any boxes with region info attached in regions. + // We have to make sure we did not leave any RenderBoxRegionInfo attached. for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; if (!region->isValid()) @@ -866,14 +692,6 @@ void RenderFlowThread::getRegionRangeForBox(const RenderBox* box, RenderRegion*& ASSERT(m_regionList.contains(startRegion) && m_regionList.contains(endRegion)); } -WebKitNamedFlow* RenderFlowThread::ensureNamedFlow() -{ - if (!m_namedFlow) - m_namedFlow = WebKitNamedFlow::create(this); - - return m_namedFlow.get(); -} - void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge) { LayoutUnit height = oldClientAfterEdge; @@ -892,12 +710,20 @@ void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterE } LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->regionRect().y() : region->regionRect().x()); LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->regionRect().maxY() : region->regionRect().maxX()); + RenderRegion::RegionState previousState = region->regionState(); RenderRegion::RegionState state = RenderRegion::RegionFit; if (flowMin <= 0) state = RenderRegion::RegionEmpty; if (flowMax > 0) state = RenderRegion::RegionOverflow; region->setRegionState(state); + // determine whether this region should dispatch a regionLayoutUpdate event + // FIXME: currently it cannot determine whether a region whose regionOverflow state remained either "fit" or "overflow" has actually + // changed, so it just assumes that those region should dispatch the event + if (previousState != state + || state == RenderRegion::RegionFit + || state == RenderRegion::RegionOverflow) + region->setDispatchRegionLayoutUpdateEvent(true); } // With the regions overflow state computed we can also set the overflow for the named flow. @@ -905,6 +731,35 @@ void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterE m_overflow = lastReg && (lastReg->regionState() == RenderRegion::RegionOverflow); } +void RenderFlowThread::regionLayoutUpdateEventTimerFired(Timer<RenderFlowThread>*) +{ + // Create a copy of region nodes, to protect them for being destroyed in the event listener + Vector<RefPtr<Node> > regionNodes; + regionNodes.reserveCapacity(m_regionList.size()); + for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { + RenderRegion* region = *iter; + ASSERT(region->node() && region->node()->isElementNode()); + // dispatch the event only for marked regions and only for those who have a listener + if (region->shouldDispatchRegionLayoutUpdateEvent()) { + regionNodes.append(region->node()); + // clear the dispatch flag here, as it is possible to be set again due to event listeners + region->setDispatchRegionLayoutUpdateEvent(false); + } + } + for (Vector<RefPtr<Node> >::const_iterator it = regionNodes.begin(); it != regionNodes.end(); ++it) { + RefPtr<Node> node = *it; + RefPtr<Document> document = node->document(); + if (!document) + continue; + RenderObject* renderer = node->renderer(); + if (renderer && renderer->isRenderRegion()) { + node->dispatchRegionLayoutUpdateEvent(); + // Layout needs to be uptodate after each event listener + document->updateLayoutIgnorePendingStylesheets(); + } + } +} + bool RenderFlowThread::regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const { ASSERT(targetRegion); @@ -939,7 +794,7 @@ bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const Rend RenderRegion* enclosingBoxEndRegion = 0; getRegionRangeForBox(enclosingBox, enclosingBoxStartRegion, enclosingBoxEndRegion); if (!regionInRange(region, enclosingBoxStartRegion, enclosingBoxEndRegion)) - return false; + return false; if (object->isBox()) return true; @@ -971,4 +826,3 @@ bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const Rend } } // namespace WebCore - diff --git a/Source/WebCore/rendering/RenderFlowThread.h b/Source/WebCore/rendering/RenderFlowThread.h index b958eb164..953939cd6 100644 --- a/Source/WebCore/rendering/RenderFlowThread.h +++ b/Source/WebCore/rendering/RenderFlowThread.h @@ -36,17 +36,13 @@ #include <wtf/ListHashSet.h> #include <wtf/PassRefPtr.h> #include <wtf/UnusedParam.h> -#include <wtf/text/AtomicString.h> namespace WebCore { class RenderFlowThread; class RenderStyle; class RenderRegion; -class WebKitNamedFlow; -typedef ListHashSet<RenderFlowThread*> RenderFlowThreadList; -typedef HashCountedSet<RenderFlowThread*> RenderFlowThreadCountedSet; typedef ListHashSet<RenderRegion*> RenderRegionList; // RenderFlowThread is used to collect all the render objects that participate in a @@ -57,32 +53,24 @@ typedef ListHashSet<RenderRegion*> RenderRegionList; class RenderFlowThread: public RenderBlock { public: - RenderFlowThread(Node*, const AtomicString& flowThread); - + RenderFlowThread(Node*); + virtual ~RenderFlowThread() { }; + virtual bool isRenderFlowThread() const { return true; } virtual void layout(); - AtomicString flowThread() const { return m_flowThread; } - - // Always create a RenderLayer for the RenderFlowThread, so that we - // can easily avoid to draw it's children directly. + // Always create a RenderLayer for the RenderFlowThread so that we + // can easily avoid drawing the children directly. virtual bool requiresLayer() const { return true; } - - RenderObject* nextRendererForNode(Node*) const; - RenderObject* previousRendererForNode(Node*) const; - void addFlowChild(RenderObject* newChild, RenderObject* beforeChild = 0); - void removeFlowChild(RenderObject*); void removeFlowChildInfo(RenderObject*); - bool hasChildren() const { return !m_flowThreadChildList.isEmpty(); } #ifndef NDEBUG - bool hasChild(RenderObject* child) const { return m_flowThreadChildList.contains(child); } bool hasChildInfo(RenderObject* child) const { return child && child->isBox() && m_regionRangeMap.contains(toRenderBox(child)); } #endif - void addRegionToThread(RenderRegion*); - void removeRegionFromThread(RenderRegion*); + virtual void addRegionToThread(RenderRegion*); + virtual void removeRegionFromThread(RenderRegion*); const RenderRegionList& renderRegionList() const { return m_regionList; } void computeLogicalWidth(); @@ -101,8 +89,6 @@ public: void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - void pushDependencies(RenderFlowThreadList&); - void repaintRectangleInRegions(const LayoutRect&, bool immediate); LayoutUnit regionLogicalTopForLine(LayoutUnit position) const; @@ -132,7 +118,7 @@ public: void clearRenderBoxCustomStyle(const RenderBox*, const RenderRegion* oldStartRegion = 0, const RenderRegion* oldEndRegion = 0, const RenderRegion* newStartRegion = 0, const RenderRegion* newEndRegion = 0); - WebKitNamedFlow* ensureNamedFlow(); + void computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge); bool overflow() const { return m_overflow; } @@ -140,22 +126,13 @@ public: // Check if the object is in region and the region is part of this flow thread. bool objectInFlowRegion(const RenderObject*, const RenderRegion*) const; -private: - virtual const char* renderName() const { return "RenderFlowThread"; } - - bool dependsOn(RenderFlowThread* otherRenderFlowThread) const; - void addDependencyOnFlowThread(RenderFlowThread*); - void removeDependencyOnFlowThread(RenderFlowThread*); - void checkInvalidRegions(); +protected: + virtual const char* renderName() const = 0; bool shouldRepaint(const LayoutRect&) const; - + void regionLayoutUpdateEventTimerFired(Timer<RenderFlowThread>*); bool regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const; - typedef ListHashSet<RenderObject*> FlowThreadChildList; - FlowThreadChildList m_flowThreadChildList; - - AtomicString m_flowThread; RenderRegionList m_regionList; class RenderRegionRange { @@ -184,16 +161,6 @@ private: RenderRegion* m_endRegion; }; - // Observer flow threads have invalid regions that depend on the state of this thread - // to re-validate their regions. Keeping a set of observer threads make it easy - // to notify them when a region was removed from this flow. - RenderFlowThreadCountedSet m_observerThreadsSet; - - // Some threads need to have a complete layout before we layout this flow. - // That's because they contain a RenderRegion that should display this thread. The set makes it - // easy to sort the order of threads layout. - RenderFlowThreadCountedSet m_layoutBeforeThreadsSet; - // A maps from RenderBox typedef HashMap<const RenderBox*, RenderRegionRange> RenderRegionRangeMap; RenderRegionRangeMap m_regionRangeMap; @@ -203,7 +170,7 @@ private: bool m_regionsHaveUniformLogicalWidth; bool m_regionsHaveUniformLogicalHeight; bool m_overflow; - RefPtr<WebKitNamedFlow> m_namedFlow; + Timer<RenderFlowThread> m_regionLayoutUpdateEventTimer; }; inline RenderFlowThread* toRenderFlowThread(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderFrameBase.cpp b/Source/WebCore/rendering/RenderFrameBase.cpp index b95e44755..046288bff 100644 --- a/Source/WebCore/rendering/RenderFrameBase.cpp +++ b/Source/WebCore/rendering/RenderFrameBase.cpp @@ -78,9 +78,9 @@ void RenderFrameBase::layoutWithFlattening(bool fixedWidth, bool fixedHeight) // expand the frame by setting frame height = content height if (isScrollable || !fixedHeight || childRoot->isFrameSet()) - setHeight(max(height(), childFrameView->contentsHeight() + vBorder)); + setHeight(max<LayoutUnit>(height(), childFrameView->contentsHeight() + vBorder)); if (isScrollable || !fixedWidth || childRoot->isFrameSet()) - setWidth(max(width(), childFrameView->contentsWidth() + hBorder)); + setWidth(max<LayoutUnit>(width(), childFrameView->contentsWidth() + hBorder)); updateWidgetPosition(); diff --git a/Source/WebCore/rendering/RenderFrameSet.cpp b/Source/WebCore/rendering/RenderFrameSet.cpp index bcce93ef8..e02c06689 100644 --- a/Source/WebCore/rendering/RenderFrameSet.cpp +++ b/Source/WebCore/rendering/RenderFrameSet.cpp @@ -215,7 +215,7 @@ void RenderFrameSet::layOutAxis(GridAxis& axis, const Length* grid, int availabl // Count the total length of all of the fixed columns/rows -> totalFixed // Count the number of columns/rows which are fixed -> countFixed if (grid[i].isFixed()) { - gridLayout[i] = max(grid[i].value(), 0); + gridLayout[i] = max(grid[i].intValue(), 0); totalFixed += gridLayout[i]; countFixed++; } @@ -223,7 +223,7 @@ void RenderFrameSet::layOutAxis(GridAxis& axis, const Length* grid, int availabl // Count the total percentage of all of the percentage columns/rows -> totalPercent // Count the number of columns/rows which are percentages -> countPercent if (grid[i].isPercent()) { - gridLayout[i] = max(grid[i].calcValue(availableLen), 0); + gridLayout[i] = max(intValueForLength(grid[i], availableLen), 0); totalPercent += gridLayout[i]; countPercent++; } @@ -231,7 +231,7 @@ void RenderFrameSet::layOutAxis(GridAxis& axis, const Length* grid, int availabl // Count the total relative of all the relative columns/rows -> totalRelative // Count the number of columns/rows which are relative -> countRelative if (grid[i].isRelative()) { - totalRelative += max(grid[i].value(), 1); + totalRelative += max(grid[i].intValue(), 1); countRelative++; } } @@ -276,7 +276,7 @@ void RenderFrameSet::layOutAxis(GridAxis& axis, const Length* grid, int availabl for (int i = 0; i < gridLen; ++i) { if (grid[i].isRelative()) { - gridLayout[i] = (max(grid[i].value(), 1) * remainingRelative) / totalRelative; + gridLayout[i] = (max(grid[i].intValue(), 1) * remainingRelative) / totalRelative; remainingLen -= gridLayout[i]; lastRelative = i; } @@ -472,8 +472,8 @@ void RenderFrameSet::layout() setHeight(view()->viewHeight()); } - size_t cols = frameSet()->totalCols(); - size_t rows = frameSet()->totalRows(); + unsigned cols = frameSet()->totalCols(); + unsigned rows = frameSet()->totalRows(); if (m_rows.m_sizes.size() != rows || m_cols.m_sizes.size() != cols) { m_rows.resize(rows); diff --git a/Source/WebCore/rendering/RenderFullScreen.cpp b/Source/WebCore/rendering/RenderFullScreen.cpp index 1d689f5c9..e0507388d 100644 --- a/Source/WebCore/rendering/RenderFullScreen.cpp +++ b/Source/WebCore/rendering/RenderFullScreen.cpp @@ -113,8 +113,10 @@ RenderObject* RenderFullScreen::wrapRenderer(RenderObject* object, Document* doc if (RenderObject* parent = object->parent()) { parent->addChild(fullscreenRenderer, object); object->remove(); + parent->setNeedsLayoutAndPrefWidthsRecalc(); } fullscreenRenderer->addChild(object); + fullscreenRenderer->setNeedsLayoutAndPrefWidthsRecalc(); } document->setFullScreenRenderer(fullscreenRenderer); return fullscreenRenderer; @@ -127,6 +129,7 @@ void RenderFullScreen::unwrapRenderer() while ((child = firstChild())) { child->remove(); parent()->addChild(child, this); + parent()->setNeedsLayoutAndPrefWidthsRecalc(); } } if (placeholder()) @@ -140,7 +143,7 @@ void RenderFullScreen::setPlaceholder(RenderBlock* placeholder) m_placeholder = placeholder; } -void RenderFullScreen::createPlaceholder(PassRefPtr<RenderStyle> style, const IntRect& frameRect) +void RenderFullScreen::createPlaceholder(PassRefPtr<RenderStyle> style, const LayoutRect& frameRect) { if (style->width().isAuto()) style->setWidth(Length(frameRect.width(), Fixed)); @@ -150,8 +153,10 @@ void RenderFullScreen::createPlaceholder(PassRefPtr<RenderStyle> style, const In if (!m_placeholder) { m_placeholder = new (document()->renderArena()) RenderFullScreenPlaceholder(this); m_placeholder->setStyle(style); - if (parent()) + if (parent()) { parent()->addChild(m_placeholder, this); + parent()->setNeedsLayoutAndPrefWidthsRecalc(); + } } else m_placeholder->setStyle(style); } diff --git a/Source/WebCore/rendering/RenderFullScreen.h b/Source/WebCore/rendering/RenderFullScreen.h index 7968792b2..d0aac50ac 100644 --- a/Source/WebCore/rendering/RenderFullScreen.h +++ b/Source/WebCore/rendering/RenderFullScreen.h @@ -39,7 +39,7 @@ public: void setPlaceholder(RenderBlock*); RenderBlock* placeholder() { return m_placeholder; } - void createPlaceholder(PassRefPtr<RenderStyle>, const IntRect& frameRect); + void createPlaceholder(PassRefPtr<RenderStyle>, const LayoutRect& frameRect); static RenderObject* wrapRenderer(RenderObject* renderer, Document*); diff --git a/Source/WebCore/rendering/RenderHTMLCanvas.cpp b/Source/WebCore/rendering/RenderHTMLCanvas.cpp index 0df9fe998..33116989e 100644 --- a/Source/WebCore/rendering/RenderHTMLCanvas.cpp +++ b/Source/WebCore/rendering/RenderHTMLCanvas.cpp @@ -88,7 +88,7 @@ void RenderHTMLCanvas::canvasSizeChanged() if (!preferredLogicalWidthsDirty()) setPreferredLogicalWidthsDirty(true); - IntSize oldSize = size(); + LayoutSize oldSize = size(); computeLogicalWidth(); computeLogicalHeight(); if (oldSize == size()) diff --git a/Source/WebCore/rendering/RenderIFrame.cpp b/Source/WebCore/rendering/RenderIFrame.cpp index 743e3f4c2..ffd50aeb8 100644 --- a/Source/WebCore/rendering/RenderIFrame.cpp +++ b/Source/WebCore/rendering/RenderIFrame.cpp @@ -57,7 +57,7 @@ void RenderIFrame::computeLogicalHeight() if (!view) return; int border = borderTop() + borderBottom(); - setHeight(max(height(), view->contentsHeight() + border)); + setHeight(max<LayoutUnit>(height(), view->contentsHeight() + border)); } } @@ -75,7 +75,7 @@ void RenderIFrame::computeLogicalWidth() if (!view) return; LayoutUnit border = borderLeft() + borderRight(); - setWidth(max(width(), view->contentsWidth() + border)); + setWidth(max<LayoutUnit>(width(), view->contentsWidth() + border)); } } @@ -85,24 +85,20 @@ bool RenderIFrame::flattenFrame() return false; HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(node()); - bool isScrollable = element->scrollingMode() != ScrollbarAlwaysOff; - - if (style()->width().isFixed() && style()->height().isFixed()) { - if (!isScrollable) - return false; - if (style()->width().value() <= 0 || style()->height().value() <= 0) - return false; - } - Frame* frame = element->document()->frame(); + bool enabled = frame && frame->settings() && frame->settings()->frameFlatteningEnabled(); if (!enabled || !frame->page()) return false; - FrameView* view = frame->page()->mainFrame()->view(); - if (!view) - return false; + if (style()->width().isFixed() && style()->height().isFixed()) { + // Do not flatten iframes with scrolling="no". + if (element->scrollingMode() == ScrollbarAlwaysOff) + return false; + if (style()->width().value() <= 0 || style()->height().value() <= 0) + return false; + } // Do not flatten offscreen inner frames during frame flattening, as flattening might make them visible. IntRect boundingRect = absoluteBoundingBoxRectIgnoringTransforms(); diff --git a/Source/WebCore/rendering/RenderIFrame.h b/Source/WebCore/rendering/RenderIFrame.h index b6b30c9ea..fe6631e36 100644 --- a/Source/WebCore/rendering/RenderIFrame.h +++ b/Source/WebCore/rendering/RenderIFrame.h @@ -34,6 +34,8 @@ class RenderIFrame : public RenderFrameBase { public: explicit RenderIFrame(Element*); + bool flattenFrame(); + private: virtual void computeLogicalHeight(); virtual void computeLogicalWidth(); @@ -44,8 +46,6 @@ private: virtual const char* renderName() const { return "RenderPartObject"; } // Lying for now to avoid breaking tests - bool flattenFrame(); - }; inline RenderIFrame* toRenderIFrame(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp index 6406f6f66..35caaff29 100644 --- a/Source/WebCore/rendering/RenderImage.cpp +++ b/Source/WebCore/rendering/RenderImage.cpp @@ -6,6 +6,7 @@ * (C) 2006 Samuel Weinig (sam.weinig@gmail.com) * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) Research In Motion Limited 2011-2012. 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 @@ -39,7 +40,7 @@ #include "HTMLNames.h" #include "HitTestResult.h" #include "Page.h" -#include "RenderLayer.h" +#include "PaintInfo.h" #include "RenderView.h" #include "SVGImage.h" #include <wtf/UnusedParam.h> @@ -175,7 +176,7 @@ void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect) imageDimensionsChanged(imageSizeChanged, rect); } -bool RenderImage::updateIntrinsicSizeIfNeeded(const LayoutSize& newSize, bool imageSizeChanged) +bool RenderImage::updateIntrinsicSizeIfNeeded(const IntSize& newSize, bool imageSizeChanged) { if (newSize == intrinsicSize() && !imageSizeChanged) return false; @@ -226,10 +227,8 @@ void RenderImage::imageDimensionsChanged(bool imageSizeChanged, const IntRect* r repaintRectangle(repaintRect); #if USE(ACCELERATED_COMPOSITING) - if (hasLayer()) { - // Tell any potential compositing layers that the image needs updating. - layer()->contentChanged(RenderLayer::ImageChanged); - } + // Tell any potential compositing layers that the image needs updating. + contentChanged(ImageChanged); #endif } } @@ -243,10 +242,10 @@ void RenderImage::notifyFinished(CachedResource* newImage) return; #if USE(ACCELERATED_COMPOSITING) - if (newImage == m_imageResource->cachedImage() && hasLayer()) { + if (newImage == m_imageResource->cachedImage()) { // tell any potential compositing layers // that the image is done and they can reference it directly. - layer()->contentChanged(RenderLayer::ImageChanged); + contentChanged(ImageChanged); } #else UNUSED_PARAM(newImage); @@ -306,7 +305,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf if (centerY < 0) centerY = 0; imageOffset = LayoutSize(leftBorder + leftPad + centerX + 1, topBorder + topPad + centerY + 1); - context->drawImage(image.get(), style()->colorSpace(), IntRect(roundedIntPoint(paintOffset + imageOffset), imageSize)); + context->drawImage(image.get(), style()->colorSpace(), IntRect(roundedIntPoint(paintOffset + imageOffset), imageSize), CompositeSourceOver, shouldRespectImageOrientation()); errorPictureDrawn = true; } @@ -416,18 +415,19 @@ void RenderImage::areaElementFocusChanged(HTMLAreaElement* element) void RenderImage::paintIntoRect(GraphicsContext* context, const LayoutRect& rect) { - if (!m_imageResource->hasImage() || m_imageResource->errorOccurred() || rect.width() <= 0 || rect.height() <= 0) + IntRect alignedRect = pixelSnappedIntRect(rect); + if (!m_imageResource->hasImage() || m_imageResource->errorOccurred() || alignedRect.width() <= 0 || alignedRect.height() <= 0) return; - RefPtr<Image> img = m_imageResource->image(rect.width(), rect.height()); + RefPtr<Image> img = m_imageResource->image(alignedRect.width(), alignedRect.height()); if (!img || img->isNull()) return; HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(node()) : 0; CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver; Image* image = m_imageResource->image().get(); - bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, rect.size()); - context->drawImage(m_imageResource->image(rect.width(), rect.height()).get(), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling); + bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size()); + context->drawImage(m_imageResource->image(alignedRect.width(), alignedRect.height()).get(), style()->colorSpace(), alignedRect, compositeOperator, shouldRespectImageOrientation(), useLowQualityScaling); } bool RenderImage::backgroundIsObscured() const @@ -469,7 +469,7 @@ HTMLMapElement* RenderImage::imageMap() const bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { - HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding()); + HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding(), result.shadowContentFilterPolicy()); bool inside = RenderReplaced::nodeAtPoint(request, tempResult, pointInContainer, accumulatedOffset, hitTestAction); if (tempResult.innerNode() && node()) { @@ -502,52 +502,34 @@ void RenderImage::updateAltText() m_altText = static_cast<HTMLImageElement*>(node())->altText(); } -LayoutUnit RenderImage::computeReplacedLogicalWidth(bool includeMaxWidth) const +void RenderImage::layout() { - // If we've got an explicit width/height assigned, propagate it to the image resource. - if (style()->logicalWidth().isSpecified() && style()->logicalHeight().isSpecified()) { - LayoutUnit width = RenderReplaced::computeReplacedLogicalWidth(includeMaxWidth); - m_imageResource->setContainerSizeForRenderer(IntSize(width, computeReplacedLogicalHeight())); - return width; - } - - IntSize containerSize; - if (m_imageResource->imageHasRelativeWidth() || m_imageResource->imageHasRelativeHeight()) { - // Propagate the containing block size to the image resource, otherwhise we can't compute our own intrinsic size, if it's relative. - RenderObject* containingBlock = isPositioned() ? container() : this->containingBlock(); - if (containingBlock->isBox()) { - RenderBox* box = toRenderBox(containingBlock); - containerSize = IntSize(box->availableWidth(), box->availableHeight()); // Already contains zooming information. - } - } else { - // Propagate the current zoomed image size to the image resource, otherwhise the image size will remain the same on-screen. - CachedImage* cachedImage = m_imageResource->cachedImage(); - if (cachedImage && cachedImage->image()) { - containerSize = cachedImage->image()->size(); - // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 - containerSize.setWidth(static_cast<LayoutUnit>(containerSize.width() * style()->effectiveZoom())); - containerSize.setHeight(static_cast<LayoutUnit>(containerSize.height() * style()->effectiveZoom())); - } - } + RenderReplaced::layout(); - if (!containerSize.isEmpty()) { + // Propagate container size to image resource. + IntSize containerSize(contentWidth(), contentHeight()); + if (!containerSize.isEmpty()) m_imageResource->setContainerSizeForRenderer(containerSize); - const_cast<RenderImage*>(this)->updateIntrinsicSizeIfNeeded(containerSize, false); - } - - return RenderReplaced::computeReplacedLogicalWidth(includeMaxWidth); } void RenderImage::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const { - // Assure this method is never used for SVGImages. - ASSERT(!embeddedContentBox()); - isPercentageIntrinsicSize = false; - CachedImage* cachedImage = m_imageResource ? m_imageResource->cachedImage() : 0; - if (!cachedImage || !cachedImage->image()) + RenderReplaced::computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); + + // Our intrinsicSize is empty if we're rendering generated images with relative width/height. Figure out the right intrinsic size to use. + if (intrinsicSize.isEmpty() && (m_imageResource->imageHasRelativeWidth() || m_imageResource->imageHasRelativeHeight())) { + RenderObject* containingBlock = isPositioned() ? container() : this->containingBlock(); + if (containingBlock->isBox()) { + RenderBox* box = toRenderBox(containingBlock); + intrinsicSize.setWidth(box->availableLogicalWidth()); + intrinsicSize.setHeight(box->availableLogicalHeight()); + } + } + // Don't compute an intrinsic ratio to preserve historical WebKit behavior if we're painting alt text and/or a broken image. + if (m_imageResource && m_imageResource->errorOccurred()) { + intrinsicRatio = 1; return; - intrinsicSize = cachedImage->image()->size(); - intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); + } } bool RenderImage::needsPreferredWidthsRecalculation() const diff --git a/Source/WebCore/rendering/RenderImage.h b/Source/WebCore/rendering/RenderImage.h index 489ceb13a..11197cce1 100644 --- a/Source/WebCore/rendering/RenderImage.h +++ b/Source/WebCore/rendering/RenderImage.h @@ -68,6 +68,7 @@ protected: virtual void paintIntoRect(GraphicsContext*, const LayoutRect&); virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void layout(); virtual void intrinsicSizeChanged() { @@ -90,11 +91,9 @@ private: virtual void notifyFinished(CachedResource*); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); - virtual LayoutUnit computeReplacedLogicalWidth(bool includeMaxWidth = true) const; - IntSize imageSizeForError(CachedImage*) const; void imageDimensionsChanged(bool imageSizeChanged, const IntRect* = 0); - bool updateIntrinsicSizeIfNeeded(const LayoutSize&, bool imageSizeChanged); + bool updateIntrinsicSizeIfNeeded(const IntSize&, bool imageSizeChanged); void paintAreaElementFocusRing(PaintInfo&); diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp index 0a5a65ee9..4449d72e3 100644 --- a/Source/WebCore/rendering/RenderInline.cpp +++ b/Source/WebCore/rendering/RenderInline.cpp @@ -146,9 +146,8 @@ static void updateStyleOfAnonymousBlockContinuations(RenderObject* block, const RenderInline* cont = toRenderBlock(block)->inlineElementContinuation(); if (oldStyle->position() == RelativePosition && hasRelPositionedInlineAncestor(cont)) continue; - RefPtr<RenderStyle> blockStyle = RenderStyle::createAnonymousStyle(block->style()); + RefPtr<RenderStyle> blockStyle = RenderStyle::createAnonymousStyleWithDisplay(block->style(), BLOCK); blockStyle->setPosition(newStyle->position()); - blockStyle->setDisplay(BLOCK); block->setStyle(blockStyle); } } @@ -281,8 +280,7 @@ void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderOb // inline into continuations. This involves creating an anonymous block box to hold // |newChild|. We then make that block box a continuation of this inline. We take all of // the children after |beforeChild| and put them in a clone of this object. - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); - newStyle->setDisplay(BLOCK); + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK); // If inside an inline affected by relative positioning the block needs to be affected by it too. // Giving the block a layer like this allows it to collect the x/y offsets from inline parents later. @@ -426,7 +424,7 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox madeNewBeforeBlock = true; } - RenderBlock* post = block->createAnonymousBlockWithSameTypeAs(pre); + RenderBlock* post = toRenderBlock(pre->createAnonymousBoxWithSameTypeAs(block)); RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling(); if (madeNewBeforeBlock) @@ -701,7 +699,9 @@ static LayoutUnit computeMargin(const RenderInline* renderer, const Length& marg if (margin.isFixed()) return margin.value(); if (margin.isPercent()) - return margin.calcMinValue(max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth())); + return minimumValueForLength(margin, max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth())); + if (margin.isViewportPercentage()) + return valueForLength(margin, 0, renderer->view()); return 0; } @@ -785,14 +785,14 @@ VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point) return RenderBoxModelObject::positionForPoint(point); } -LayoutRect RenderInline::linesBoundingBox() const +IntRect RenderInline::linesBoundingBox() const { if (!alwaysCreateLineBoxes()) { ASSERT(!firstLineBox()); - return enclosingLayoutRect(culledInlineBoundingBox(this)); + return enclosingIntRect(culledInlineBoundingBox(this)); } - LayoutRect result; + IntRect result; // See <rdar://problem/5289721>, for an unknown reason the linked list here is sometimes inconsistent, first is non-zero and last is zero. We have been // unable to reproduce this at all (and consequently unable to figure ot why this is happening). The assert will hopefully catch the problem in debug @@ -815,7 +815,7 @@ LayoutRect RenderInline::linesBoundingBox() const float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide; float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x; float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide; - result = enclosingLayoutRect(FloatRect(x, y, width, height)); + result = enclosingIntRect(FloatRect(x, y, width, height)); } return result; @@ -976,8 +976,8 @@ LayoutRect RenderInline::linesVisualOverflowBoundingBox() const return LayoutRect(); // Return the width of the minimal left side and the maximal right side. - LayoutUnit logicalLeftSide = numeric_limits<LayoutUnit>::max(); - LayoutUnit logicalRightSide = numeric_limits<LayoutUnit>::min(); + LayoutUnit logicalLeftSide = MAX_LAYOUT_UNIT; + LayoutUnit logicalRightSide = MIN_LAYOUT_UNIT; for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow()); logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow()); @@ -1011,18 +1011,27 @@ LayoutRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* rep // Now invalidate a rectangle. LayoutUnit ow = style() ? style()->outlineSize() : 0; - + + bool hitRepaintContainer = false; + // We need to add in the relative position offsets of any inlines (including us) up to our // containing block. RenderBlock* cb = containingBlock(); for (const RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb; inlineFlow = inlineFlow->parent()) { - if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer()) + if (inlineFlow == repaintContainer) { + hitRepaintContainer = true; + break; + } + if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer()) toRenderInline(inlineFlow)->layer()->relativePositionOffset(left, top); } LayoutRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2); + if (hitRepaintContainer || !cb) + return r; + if (cb->hasColumns()) cb->adjustRectForColumns(r); @@ -1036,11 +1045,8 @@ LayoutRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* rep LayoutRect boxRect(LayoutPoint(), cb->cachedSizeForOverflowClip()); r = intersection(repaintRect, boxRect); } - - // FIXME: need to ensure that we compute the correct repaint rect when the repaint container - // is an inline. - if (repaintContainer != this) - cb->computeRectForRepaint(repaintContainer, r); + + cb->computeRectForRepaint(repaintContainer, r); if (ow) { for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { @@ -1050,7 +1056,7 @@ LayoutRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* rep } } - if (continuation() && !continuation()->isInline()) { + if (continuation() && !continuation()->isInline() && continuation()->parent()) { LayoutRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow); r.unite(contRect); } @@ -1104,18 +1110,6 @@ void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, } } -#if ENABLE(CSS_FILTERS) - if (style()->hasFilterOutsets()) { - LayoutUnit topOutset; - LayoutUnit rightOutset; - LayoutUnit bottomOutset; - LayoutUnit leftOutset; - style()->filter().getOutsets(topOutset, rightOutset, bottomOutset, leftOutset); - rect.move(-leftOutset, -topOutset); - rect.expand(leftOutset + rightOutset, topOutset + bottomOutset); - } -#endif - if (style()->position() == RelativePosition && layer()) { // Apply the relative position offset when invalidating a rectangle. The layer // is translated, but the render box isn't, so we need to do this to get the @@ -1168,7 +1162,7 @@ LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const Layo return offset; } -void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, bool* wasFixed) const +void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, ApplyContainerFlipOrNot applyContainerFlip, bool* wasFixed) const { if (repaintContainer == this) return; @@ -1189,9 +1183,11 @@ void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b if (!o) return; - IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint()); - if (o->isBox() && o->style()->isFlippedBlocksWritingMode()) - transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(roundedIntPoint(transformState.mappedPoint())) - centerPoint); + if (applyContainerFlip && o->isBox() && o->style()->isFlippedBlocksWritingMode()) { + IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint()); + transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(centerPoint) - centerPoint); + applyContainerFlip = DoNotApplyContainerFlip; + } LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint())); @@ -1211,7 +1207,7 @@ void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b return; } - o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, wasFixed); + o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, applyContainerFlip, wasFixed); } void RenderInline::updateDragState(bool dragOn) @@ -1307,10 +1303,10 @@ LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode /*directio if (firstLine && document()->usesFirstLineRules()) { RenderStyle* s = style(firstLine); if (s != style()) - return s->computedLineHeight(); + return s->computedLineHeight(view()); } - return style()->computedLineHeight(); + return style()->computedLineHeight(view()); } LayoutUnit RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const @@ -1457,6 +1453,8 @@ void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const L LayoutSize(thisline.width() + offset, thisline.height() + offset)); IntRect pixelSnappedBox = pixelSnappedIntRect(box); + IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0); + IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0); // left edge drawLineForBoxSide(graphicsContext, @@ -1486,7 +1484,7 @@ void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const L drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.y() - outlineWidth, - min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : paintOffset.x() + lastline.x())), + min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())), pixelSnappedBox.y(), BSTop, outlineColor, outlineStyle, outlineWidth, @@ -1495,7 +1493,7 @@ void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const L if (lastline.maxX() < thisline.maxX()) drawLineForBoxSide(graphicsContext, - max(lastline.isEmpty() ? -1000000 : paintOffset.x() + lastline.maxX(), pixelSnappedBox.x() - outlineWidth), + max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth), pixelSnappedBox.y() - outlineWidth, pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.y(), @@ -1519,7 +1517,7 @@ void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const L drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.maxY(), - min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? paintOffset.x() + nextline.x() + 1 : 1000000), + min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000), pixelSnappedBox.maxY() + outlineWidth, BSBottom, outlineColor, outlineStyle, outlineWidth, @@ -1528,7 +1526,7 @@ void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const L if (nextline.maxX() < thisline.maxX()) drawLineForBoxSide(graphicsContext, - max(!nextline.isEmpty() ? paintOffset.x() + nextline.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth), + max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth), pixelSnappedBox.maxY(), pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.maxY() + outlineWidth, diff --git a/Source/WebCore/rendering/RenderInline.h b/Source/WebCore/rendering/RenderInline.h index 0cb026448..190cbec41 100644 --- a/Source/WebCore/rendering/RenderInline.h +++ b/Source/WebCore/rendering/RenderInline.h @@ -51,7 +51,7 @@ public: virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&) const; - LayoutRect linesBoundingBox() const; + IntRect linesBoundingBox() const; LayoutRect linesVisualOverflowBoundingBox() const; InlineFlowBox* createAndAppendInlineFlowBox(); @@ -130,14 +130,14 @@ private: virtual LayoutRect rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, LayoutUnit outlineWidth) const; virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect&, bool fixed) const; - virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&, bool* wasFixed = 0) const; + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; virtual VisiblePosition positionForPoint(const LayoutPoint&); - virtual LayoutRect borderBoundingBox() const + virtual IntRect borderBoundingBox() const { - LayoutRect boundingBox = linesBoundingBox(); - return LayoutRect(0, 0, boundingBox.width(), boundingBox.height()); + IntRect boundingBox = linesBoundingBox(); + return IntRect(0, 0, boundingBox.width(), boundingBox.height()); } virtual InlineFlowBox* createInlineFlowBox(); // Subclassed by SVG and Ruby diff --git a/Source/WebCore/rendering/RenderInputSpeech.cpp b/Source/WebCore/rendering/RenderInputSpeech.cpp index 0f14925bb..370ae0aec 100644 --- a/Source/WebCore/rendering/RenderInputSpeech.cpp +++ b/Source/WebCore/rendering/RenderInputSpeech.cpp @@ -46,7 +46,7 @@ static const float defaultSpeechButtonSize = 16; static const float minSpeechButtonSize = 8; static const float maxSpeechButtonSize = 40; -void RenderInputSpeech::adjustInputFieldSpeechButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) +void RenderInputSpeech::adjustInputFieldSpeechButtonStyle(StyleResolver*, RenderStyle* style, Element*) { // Scale the button size based on the font size. float fontScale = style->fontSize() / defaultControlFontPixelSize; @@ -66,19 +66,19 @@ bool RenderInputSpeech::paintInputFieldSpeechButton(RenderObject* object, const if (!input->renderer()->isBox()) return false; RenderBox* inputRenderBox = toRenderBox(input->renderer()); - IntRect inputContentBox = inputRenderBox->contentBoxRect(); + LayoutRect inputContentBox = inputRenderBox->contentBoxRect(); // Make sure the scaled button stays square and will fit in its parent's box. - int buttonSize = std::min(inputContentBox.width(), std::min(inputContentBox.height(), rect.height())); + LayoutUnit buttonSize = std::min(inputContentBox.width(), std::min<LayoutUnit>(inputContentBox.height(), rect.height())); // Calculate button's coordinates relative to the input element. // Center the button vertically. Round up though, so if it has to be one pixel off-center, it will // be one pixel closer to the bottom of the field. This tends to look better with the text. - IntRect buttonRect(object->offsetFromAncestorContainer(inputRenderBox).width(), - inputContentBox.y() + (inputContentBox.height() - buttonSize + 1) / 2, - buttonSize, buttonSize); + LayoutRect buttonRect(object->offsetFromAncestorContainer(inputRenderBox).width(), + inputContentBox.y() + (inputContentBox.height() - buttonSize + 1) / 2, + buttonSize, buttonSize); // Compute an offset between the part renderer and the input renderer. - IntSize offsetFromInputRenderer = -(object->offsetFromAncestorContainer(inputRenderBox)); + LayoutSize offsetFromInputRenderer = -(object->offsetFromAncestorContainer(inputRenderBox)); // Move the rect into partRenderer's coords. buttonRect.move(offsetFromInputRenderer); // Account for the local drawing offset. @@ -94,7 +94,7 @@ bool RenderInputSpeech::paintInputFieldSpeechButton(RenderObject* object, const image = imageStateRecording.get(); else if (speechButton->state() == InputFieldSpeechButtonElement::Recognizing) image = imageStateWaiting.get(); - paintInfo.context->drawImage(image, object->style()->colorSpace(), buttonRect); + paintInfo.context->drawImage(image, object->style()->colorSpace(), pixelSnappedIntRect(buttonRect)); return false; } diff --git a/Source/WebCore/rendering/RenderInputSpeech.h b/Source/WebCore/rendering/RenderInputSpeech.h index 63ef8ae65..f37b836f4 100644 --- a/Source/WebCore/rendering/RenderInputSpeech.h +++ b/Source/WebCore/rendering/RenderInputSpeech.h @@ -39,7 +39,7 @@ namespace WebCore { class RenderInputSpeech { public: - static void adjustInputFieldSpeechButtonStyle(CSSStyleSelector*, RenderStyle*, Element*); + static void adjustInputFieldSpeechButtonStyle(StyleResolver*, RenderStyle*, Element*); static bool paintInputFieldSpeechButton(RenderObject*, const PaintInfo&, const IntRect&); }; diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index 9cf767ee8..33379cf24 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -46,7 +46,6 @@ #include "ColumnInfo.h" #include "CSSPropertyNames.h" -#include "CSSStyleSelector.h" #include "Chrome.h" #include "Document.h" #include "DocumentEventQueue.h" @@ -92,6 +91,7 @@ #include "Settings.h" #include "SourceGraphic.h" #include "StylePropertySet.h" +#include "StyleResolver.h" #include "TextStream.h" #include "TransformationMatrix.h" #include "TranslateTransformOperation.h" @@ -165,7 +165,13 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer) , m_mustOverlapCompositedLayers(false) #endif , m_containsDirtyOverlayScrollbars(false) +#if !ASSERT_DISABLED + , m_layerListMutationAllowed(true) +#endif , m_canSkipRepaintRectsUpdateOnScroll(renderer->isTableCell()) +#if ENABLE(CSS_FILTERS) + , m_hasFilterInfo(false) +#endif , m_renderer(renderer) , m_parent(0) , m_previous(0) @@ -194,6 +200,14 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer) m_visibleContentStatusDirty = false; m_hasVisibleContent = renderer->style()->visibility() == VISIBLE; } + + Node* node = renderer->node(); + if (node && node->isElementNode()) { + // We save and restore only the scrollOffset as the other scroll values are recalculated. + Element* element = toElement(node); + m_scrollOffset = element->savedLayerScrollOffset(); + element->setSavedLayerScrollOffset(IntSize()); + } } RenderLayer::~RenderLayer() @@ -208,11 +222,21 @@ RenderLayer::~RenderLayer() frameView->removeScrollableArea(this); } + if (!m_renderer->documentBeingDestroyed()) { + Node* node = m_renderer->node(); + if (node && node->isElementNode()) + toElement(node)->setSavedLayerScrollOffset(m_scrollOffset); + } + destroyScrollbar(HorizontalScrollbar); destroyScrollbar(VerticalScrollbar); if (m_reflection) removeReflection(); + +#if ENABLE(CSS_FILTERS) + removeFilterInfoIfNeeded(); +#endif // Child layers will be deleted by their corresponding render objects, so // we don't need to delete them ourselves. @@ -223,7 +247,7 @@ RenderLayer::~RenderLayer() delete m_marquee; #if USE(ACCELERATED_COMPOSITING) - clearBacking(); + clearBacking(true); #endif // Make sure we have no lingering clip rects. @@ -253,15 +277,6 @@ void RenderLayer::contentChanged(ContentChangeType changeType) } #endif // USE(ACCELERATED_COMPOSITING) -bool RenderLayer::hasAcceleratedCompositing() const -{ -#if USE(ACCELERATED_COMPOSITING) - return compositor()->hasAcceleratedCompositing(); -#else - return false; -#endif -} - bool RenderLayer::canRender3DTransforms() const { #if USE(ACCELERATED_COMPOSITING) @@ -278,14 +293,24 @@ bool RenderLayer::paintsWithFilters() const if (!renderer()->hasFilter()) return false; +#if USE(ACCELERATED_COMPOSITING) if (!isComposited()) return true; if (!m_backing || !m_backing->canCompositeFilters()) return true; +#endif return false; } + +bool RenderLayer::requiresFullLayerImageForFilters() const +{ + if (!paintsWithFilters()) + return false; + FilterEffectRenderer* filter = filterRenderer(); + return filter ? filter->hasFilterThatMovesPixels() : false; +} #endif LayoutPoint RenderLayer::computeOffsetFromRoot(bool& hasLayerOffset) const @@ -739,12 +764,13 @@ void RenderLayer::updateLayerPosition() LayoutSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done. if (renderer()->isRenderInline()) { RenderInline* inlineFlow = toRenderInline(renderer()); - LayoutRect lineBox = inlineFlow->linesBoundingBox(); + IntRect lineBox = inlineFlow->linesBoundingBox(); setSize(lineBox.size()); inlineBoundingBoxOffset = toSize(lineBox.location()); localPoint += inlineBoundingBoxOffset; } else if (RenderBox* box = renderBox()) { - setSize(box->size()); + // FIXME: Is snapping the size really needed here for the RenderBox case? + setSize(pixelSnappedIntSize(box->size(), box->location())); localPoint += box->topLeftLocationOffset(); } @@ -820,8 +846,8 @@ TransformationMatrix RenderLayer::perspectiveTransform() const const float boxWidth = borderBox.width(); const float boxHeight = borderBox.height(); - float perspectiveOriginX = style->perspectiveOriginX().calcFloatValue(boxWidth); - float perspectiveOriginY = style->perspectiveOriginY().calcFloatValue(boxHeight); + float perspectiveOriginX = floatValueForLength(style->perspectiveOriginX(), boxWidth); + float perspectiveOriginY = floatValueForLength(style->perspectiveOriginY(), boxHeight); // A perspective origin of 0,0 makes the vanishing point in the center of the element. // We want it to be in the top-left, so subtract half the height and width. @@ -844,8 +870,8 @@ FloatPoint RenderLayer::perspectiveOrigin() const const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect(); RenderStyle* style = renderer()->style(); - return FloatPoint(style->perspectiveOriginX().calcFloatValue(borderBox.width()), - style->perspectiveOriginY().calcFloatValue(borderBox.height())); + return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox.width()), + floatValueForLength(style->perspectiveOriginY(), borderBox.height())); } RenderLayer* RenderLayer::stackingContext() const @@ -934,8 +960,107 @@ RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const return 0; } + +RenderLayer* RenderLayer::enclosingCompositingLayerForRepaint(bool includeSelf) const +{ + if (includeSelf && isComposited() && !backing()->paintsIntoCompositedAncestor()) + return const_cast<RenderLayer*>(this); + + for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) { + if (curr->isComposited() && !curr->backing()->paintsIntoCompositedAncestor()) + return const_cast<RenderLayer*>(curr); + } + + return 0; +} +#endif + +#if ENABLE(CSS_FILTERS) +RenderLayer* RenderLayer::enclosingFilterLayer(bool includeSelf) const +{ + const RenderLayer* curr = includeSelf ? this : parent(); + for (; curr; curr = curr->parent()) { + if (curr->requiresFullLayerImageForFilters()) + return const_cast<RenderLayer*>(curr); + } + + return 0; +} + +RenderLayer* RenderLayer::enclosingFilterRepaintLayer() const +{ + for (const RenderLayer* curr = this; curr; curr = curr->parent()) { + if ((curr != this && curr->requiresFullLayerImageForFilters()) || curr->isComposited() || curr->isRootLayer()) + return const_cast<RenderLayer*>(curr); + } + return 0; +} + +void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect, bool immediate) +{ + if (rect.isEmpty()) + return; + + LayoutRect rectForRepaint = rect; + +#if ENABLE(CSS_FILTERS) + if (renderer()->style()->hasFilterOutsets()) { + int topOutset; + int rightOutset; + int bottomOutset; + int leftOutset; + renderer()->style()->getFilterOutsets(topOutset, rightOutset, bottomOutset, leftOutset); + rectForRepaint.move(-leftOutset, -topOutset); + rectForRepaint.expand(leftOutset + rightOutset, topOutset + bottomOutset); + } +#endif + + RenderLayerFilterInfo* filterInfo = this->filterInfo(); + ASSERT(filterInfo); + filterInfo->expandDirtySourceRect(rectForRepaint); + +#if ENABLE(CSS_SHADERS) + ASSERT(filterInfo->renderer()); + if (filterInfo->renderer()->hasCustomShaderFilter()) { + // If we have at least one custom shader, we need to update the whole bounding box of the layer, because the + // shader can address any ouput pixel. + // Note: This is only for output rect, so there's no need to expand the dirty source rect. + rectForRepaint.unite(calculateLayerBounds(this, this)); + } +#endif + + RenderLayer* parentLayer = enclosingFilterRepaintLayer(); + ASSERT(parentLayer); + FloatQuad repaintQuad(rectForRepaint); + LayoutRect parentLayerRect = renderer()->localToContainerQuad(repaintQuad, parentLayer->renderer()).enclosingBoundingBox(); + +#if USE(ACCELERATED_COMPOSITING) + if (parentLayer->isComposited()) { + if (!parentLayer->backing()->paintsIntoWindow()) { + parentLayer->setBackingNeedsRepaintInRect(parentLayerRect); + return; + } + // If the painting goes to window, redirect the painting to the parent RenderView. + parentLayer = renderer()->view()->layer(); + parentLayerRect = renderer()->localToContainerQuad(repaintQuad, parentLayer->renderer()).enclosingBoundingBox(); + } #endif + if (parentLayer->paintsWithFilters()) { + parentLayer->setFilterBackendNeedsRepaintingInRect(parentLayerRect, immediate); + return; + } + + if (parentLayer->isRootLayer()) { + RenderView* view = toRenderView(parentLayer->renderer()); + view->repaintViewRectangle(parentLayerRect, immediate); + return; + } + + ASSERT_NOT_REACHED(); +} +#endif + RenderLayer* RenderLayer::clippingRoot() const { #if USE(ACCELERATED_COMPOSITING) @@ -952,7 +1077,7 @@ RenderLayer* RenderLayer::clippingRoot() const ASSERT(current); if (current->transform() #if USE(ACCELERATED_COMPOSITING) - || current->isComposited() + || (current->isComposited() && !current->backing()->paintsIntoCompositedAncestor()) #endif ) return const_cast<RenderLayer*>(current); @@ -1480,23 +1605,9 @@ void RenderLayer::scrollTo(int x, int y) view->updateWidgetPositions(); } -#if USE(ACCELERATED_COMPOSITING) - if (compositor()->inCompositingMode()) { - // Our stacking context is guaranteed to contain all of our descendants that may need - // repositioning, so update compositing layers from there. - if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) { - if (compositor()->compositingConsultsOverlap()) - compositor()->updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor); - else { - bool isUpdateRoot = true; - compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot); - } - } - } -#endif + updateCompositingLayersAfterScroll(); RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); - Frame* frame = renderer()->frame(); if (frame) { // The caret rect needs to be invalidated after scrolling @@ -1587,9 +1698,12 @@ void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignm yOffset = max(0, min(frameView->contentsHeight(), yOffset)); frameView->setScrollPosition(IntPoint(xOffset, yOffset)); - parentLayer = ownerElement->renderer()->enclosingLayer(); - newRect.setX(rect.x() - frameView->scrollX() + frameView->x()); - newRect.setY(rect.y() - frameView->scrollY() + frameView->y()); + if (frameView->safeToPropagateScrollToParent()) { + parentLayer = ownerElement->renderer()->enclosingLayer(); + newRect.setX(rect.x() - frameView->scrollX() + frameView->x()); + newRect.setY(rect.y() - frameView->scrollY() + frameView->y()); + } else + parentLayer = 0; } } else { LayoutRect viewRect = frameView->visibleContentRect(); @@ -1617,6 +1731,24 @@ void RenderLayer::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignm frameView->resumeScheduledEvents(); } +void RenderLayer::updateCompositingLayersAfterScroll() +{ +#if USE(ACCELERATED_COMPOSITING) + if (compositor()->inCompositingMode()) { + // Our stacking context is guaranteed to contain all of our descendants that may need + // repositioning, so update compositing layers from there. + if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) { + if (compositor()->compositingConsultsOverlap()) + compositor()->updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor); + else { + bool isUpdateRoot = true; + compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot); + } + } + } +#endif +} + LayoutRect RenderLayer::getRectToExpose(const LayoutRect &visibleRect, const LayoutRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) { // Determine the appropriate X behavior. @@ -1755,9 +1887,9 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOff styledElement->setInlineStyleProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false); styledElement->setInlineStyleProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false); } - LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? zeroLayoutUnit : renderer->borderAndPaddingWidth()); + LayoutUnit baseWidth = renderer->width() - (isBoxSizingBorder ? ZERO_LAYOUT_UNIT : renderer->borderAndPaddingWidth()); baseWidth = baseWidth / zoomFactor; - styledElement->setInlineStyleProperty(CSSPropertyWidth, String::number(baseWidth + difference.width()) + "px", false); + styledElement->setInlineStyleProperty(CSSPropertyWidth, String::number(roundToInt(baseWidth + difference.width())) + "px", false); } if (resize != RESIZE_HORIZONTAL && difference.height()) { @@ -1766,9 +1898,9 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const LayoutSize& oldOff styledElement->setInlineStyleProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false); styledElement->setInlineStyleProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false); } - LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? zeroLayoutUnit : renderer->borderAndPaddingHeight()); + LayoutUnit baseHeight = renderer->height() - (isBoxSizingBorder ? ZERO_LAYOUT_UNIT : renderer->borderAndPaddingHeight()); baseHeight = baseHeight / zoomFactor; - styledElement->setInlineStyleProperty(CSSPropertyHeight, String::number(baseHeight + difference.height()) + "px", false); + styledElement->setInlineStyleProperty(CSSPropertyHeight, String::number(roundToInt(baseHeight + difference.height())) + "px", false); } document->updateLayout(); @@ -1878,7 +2010,7 @@ IntRect RenderLayer::scrollCornerRect() const bool hasVerticalBar = verticalScrollbar(); bool hasResizer = renderer()->style()->resize() != RESIZE_NONE; if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar))) - return cornerRect(this, pixelSnappedIntRect(renderBox()->borderBoxRect())); + return cornerRect(this, renderBox()->pixelSnappedBorderBoxRect()); return IntRect(); } @@ -1897,7 +2029,7 @@ IntRect RenderLayer::scrollCornerAndResizerRect() const return IntRect(); IntRect scrollCornerAndResizer = scrollCornerRect(); if (scrollCornerAndResizer.isEmpty()) - scrollCornerAndResizer = resizerCornerRect(this, pixelSnappedIntRect(box->borderBoxRect())); + scrollCornerAndResizer = resizerCornerRect(this, box->pixelSnappedBorderBoxRect()); return scrollCornerAndResizer; } @@ -1955,7 +2087,7 @@ IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scro IntSize RenderLayer::contentsSize() const { - return IntSize(const_cast<RenderLayer*>(this)->scrollWidth(), const_cast<RenderLayer*>(this)->scrollHeight()); + return IntSize(scrollWidth(), scrollHeight()); } int RenderLayer::visibleHeight() const @@ -1999,7 +2131,7 @@ LayoutUnit RenderLayer::horizontalScrollbarStart(int minX) const const RenderBox* box = renderBox(); int x = minX + box->borderLeft(); if (renderer()->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) - x += m_vBar ? m_vBar->width() : resizerCornerRect(this, box->borderBoxRect()).width(); + x += m_vBar ? m_vBar->width() : resizerCornerRect(this, box->pixelSnappedBorderBoxRect()).width(); return x; } @@ -2097,7 +2229,7 @@ bool RenderLayer::scrollsOverflow() const { if (!renderer()->isBox()) return false; - + return toRenderBox(renderer())->scrollsOverflow(); } @@ -2108,7 +2240,7 @@ bool RenderLayer::allowsScrolling() const void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar) { - if (hasScrollbar == (m_hBar != 0)) + if (hasScrollbar == hasHorizontalScrollbar()) return; if (hasScrollbar) @@ -2131,7 +2263,7 @@ void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar) void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar) { - if (hasScrollbar == (m_vBar != 0)) + if (hasScrollbar == hasVerticalScrollbar()) return; if (hasScrollbar) @@ -2202,7 +2334,7 @@ void RenderLayer::positionOverflowControls(const IntSize& offsetFromLayer) if (!box) return; - const IntRect borderBox = pixelSnappedIntRect(box->borderBoxRect()); + const IntRect borderBox = box->pixelSnappedBorderBoxRect(); const IntRect& scrollCorner = scrollCornerRect(); IntRect absBounds(borderBox.location() + offsetFromLayer, borderBox.size()); if (m_vBar) @@ -2247,18 +2379,20 @@ void RenderLayer::positionOverflowControls(const IntSize& offsetFromLayer) m_resizer->setFrameRect(resizerCornerRect(this, borderBox)); } -int RenderLayer::scrollWidth() +int RenderLayer::scrollWidth() const { + ASSERT(renderBox()); if (m_scrollDimensionsDirty) - computeScrollDimensions(); - return m_scrollSize.width(); + const_cast<RenderLayer*>(this)->computeScrollDimensions(); + return snapSizeToPixel(m_scrollSize.width(), renderBox()->clientLeft()); } -int RenderLayer::scrollHeight() +int RenderLayer::scrollHeight() const { + ASSERT(renderBox()); if (m_scrollDimensionsDirty) - computeScrollDimensions(); - return m_scrollSize.height(); + const_cast<RenderLayer*>(this)->computeScrollDimensions(); + return snapSizeToPixel(m_scrollSize.height(), renderBox()->clientTop()); } LayoutUnit RenderLayer::overflowTop() const @@ -2293,11 +2427,11 @@ LayoutUnit RenderLayer::overflowRight() const return overflowRect.maxX(); } -void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar) +void RenderLayer::computeScrollDimensions() { RenderBox* box = renderBox(); ASSERT(box); - + m_scrollDimensionsDirty = false; m_scrollOverflow.setWidth(overflowLeft() - box->borderLeft()); @@ -2305,60 +2439,47 @@ void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar) m_scrollSize.setWidth(overflowRight() - overflowLeft()); m_scrollSize.setHeight(overflowBottom() - overflowTop()); - + setScrollOrigin(IntPoint(-m_scrollOverflow.width(), -m_scrollOverflow.height())); +} - if (needHBar) - *needHBar = scrollWidth() > box->pixelSnappedClientWidth(); - if (needVBar) - *needVBar = scrollHeight() > box->pixelSnappedClientHeight(); +bool RenderLayer::hasHorizontalOverflow() const +{ + ASSERT(!m_scrollDimensionsDirty); + + return scrollWidth() > renderBox()->pixelSnappedClientWidth(); } -void RenderLayer::updateScrollInfoAfterLayout() +bool RenderLayer::hasVerticalOverflow() const { - RenderBox* box = renderBox(); - if (!box) - return; + ASSERT(!m_scrollDimensionsDirty); - m_scrollDimensionsDirty = true; - IntSize scrollOffsetOriginal(scrollXOffset(), scrollYOffset()); + return scrollHeight() > renderBox()->pixelSnappedClientHeight(); +} - bool horizontalOverflow, verticalOverflow; - computeScrollDimensions(&horizontalOverflow, &verticalOverflow); +void RenderLayer::updateScrollbarsAfterLayout() +{ + RenderBox* box = renderBox(); + ASSERT(box); - if (box->style()->overflowX() != OMARQUEE) { - // Layout may cause us to be in an invalid scroll position. In this case we need - // to pull our scroll offsets back to the max (or push them up to the min). - int newX = max(0, min<int>(scrollXOffset(), scrollWidth() - box->clientWidth())); - int newY = max(0, min<int>(scrollYOffset(), scrollHeight() - box->clientHeight())); - if (newX != scrollXOffset() || newY != scrollYOffset()) - scrollToOffset(newX, newY); - } + bool hasHorizontalOverflow = this->hasHorizontalOverflow(); + bool hasVerticalOverflow = this->hasVerticalOverflow(); - bool haveHorizontalBar = m_hBar; - bool haveVerticalBar = m_vBar; - // overflow:scroll should just enable/disable. if (m_hBar && renderer()->style()->overflowX() == OSCROLL) - m_hBar->setEnabled(horizontalOverflow); + m_hBar->setEnabled(hasHorizontalOverflow); if (m_vBar && renderer()->style()->overflowY() == OSCROLL) - m_vBar->setEnabled(verticalOverflow); + m_vBar->setEnabled(hasVerticalOverflow); - // A dynamic change from a scrolling overflow to overflow:hidden means we need to get rid of any - // scrollbars that may be present. - if (renderer()->style()->overflowX() == OHIDDEN && haveHorizontalBar) - setHasHorizontalScrollbar(false); - if (renderer()->style()->overflowY() == OHIDDEN && haveVerticalBar) - setHasVerticalScrollbar(false); - // overflow:auto may need to lay out again if scrollbars got added/removed. - bool scrollbarsChanged = (box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) || - (box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow); - if (scrollbarsChanged) { + bool autoHorizontalScrollBarChanged = box->hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow); + bool autoVerticalScrollBarChanged = box->hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow); + + if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) { if (box->hasAutoHorizontalScrollbar()) - setHasHorizontalScrollbar(horizontalOverflow); + setHasHorizontalScrollbar(hasHorizontalOverflow); if (box->hasAutoVerticalScrollbar()) - setHasVerticalScrollbar(verticalOverflow); + setHasVerticalScrollbar(hasVerticalOverflow); #if ENABLE(DASHBOARD_SUPPORT) // Force an update since we know the scrollbars have changed things. @@ -2372,24 +2493,17 @@ void RenderLayer::updateScrollInfoAfterLayout() if (!m_inOverflowRelayout) { // Our proprietary overflow: overlay value doesn't trigger a layout. m_inOverflowRelayout = true; - renderer()->setNeedsLayout(true, false); + renderer()->setNeedsLayout(true, MarkOnlyThis); if (renderer()->isRenderBlock()) { RenderBlock* block = toRenderBlock(renderer()); - block->scrollbarsChanged(box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow, - box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow); - block->layoutBlock(true); // FIXME: Need to handle positioned floats triggering extra relayouts. + block->scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged); + block->layoutBlock(true); } else renderer()->layout(); m_inOverflowRelayout = false; } } } - - // If overflow:scroll is turned into overflow:auto a bar might still be disabled (Bug 11985). - if (m_hBar && box->hasAutoHorizontalScrollbar()) - m_hBar->setEnabled(true); - if (m_vBar && box->hasAutoVerticalScrollbar()) - m_vBar->setEnabled(true); // Set up the range (and page step/line step). if (m_hBar) { @@ -2405,6 +2519,31 @@ void RenderLayer::updateScrollInfoAfterLayout() m_vBar->setProportion(clientHeight, m_scrollSize.height()); } + updateScrollableAreaSet((hasHorizontalOverflow || hasVerticalOverflow) && scrollsOverflow()); +} + +void RenderLayer::updateScrollInfoAfterLayout() +{ + RenderBox* box = renderBox(); + if (!box) + return; + + m_scrollDimensionsDirty = true; + IntSize scrollOffsetOriginal(scrollXOffset(), scrollYOffset()); + + computeScrollDimensions(); + + if (box->style()->overflowX() != OMARQUEE) { + // Layout may cause us to be at an invalid scroll position. In this case we need + // to pull our scroll offsets back to the max (or push them up to the min). + int newX = max(0, min<int>(scrollXOffset(), scrollWidth() - box->clientWidth())); + int newY = max(0, min<int>(scrollYOffset(), scrollHeight() - box->clientHeight())); + if (newX != scrollXOffset() || newY != scrollYOffset()) + scrollToOffset(newX, newY); + } + + updateScrollbarsAfterLayout(); + if (scrollOffsetOriginal != scrollOffset()) scrollToOffsetWithoutAnimation(IntPoint(scrollXOffset(), scrollYOffset())); } @@ -2534,7 +2673,7 @@ void RenderLayer::paintResizer(GraphicsContext* context, const IntPoint& paintOf RenderBox* box = renderBox(); ASSERT(box); - IntRect absRect = resizerCornerRect(this, pixelSnappedIntRect(box->borderBoxRect())); + IntRect absRect = resizerCornerRect(this, box->pixelSnappedBorderBoxRect()); absRect.moveBy(paintOffset); if (!absRect.intersects(damageRect)) return; @@ -2589,7 +2728,7 @@ bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& IntRect resizeControlRect; if (renderer()->style()->resize() != RESIZE_NONE) { - resizeControlRect = resizerCornerRect(this, pixelSnappedIntRect(box->borderBoxRect())); + resizeControlRect = resizerCornerRect(this, box->pixelSnappedBorderBoxRect()); if (resizeControlRect.contains(localPoint)) return true; } @@ -2747,7 +2886,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* context, // but we need to ensure that we don't cache clip rects computed with the wrong root in this case. if (context->updatingControlTints() || (paintBehavior & PaintBehaviorFlattenCompositingLayers)) paintFlags |= PaintLayerTemporaryClipRects; - else if (!backing()->paintingGoesToWindow() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) { + else if (!backing()->paintsIntoWindow() && !backing()->paintsIntoCompositedAncestor() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) { // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer(). return; } @@ -2761,6 +2900,10 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* context, if (!renderer()->opacity()) return; + // Non self-painting leaf layers don't need to be painted as their renderer() should properly paint itself. + if (!isSelfPaintingLayer() && !firstChild()) + return; + if (paintsWithTransparency(paintBehavior)) paintFlags |= PaintLayerHaveTransparency; @@ -2836,7 +2979,7 @@ void RenderLayer::paintLayerContentsAndReflection(RenderLayer* rootLayer, Graphi } void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* context, - const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior, + const LayoutRect& parentPaintDirtyRect, PaintBehavior paintBehavior, RenderObject* paintingRoot, RenderRegion* region, OverlapTestRequestMap* overlapTestRequests, PaintLayerFlags paintFlags) { @@ -2852,14 +2995,50 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co LayoutRect layerBounds; ClipRect damageRect, clipRectToApply, outlineRect; LayoutPoint paintOffset; + LayoutRect paintDirtyRect = parentPaintDirtyRect; + + bool useClipRect = true; + GraphicsContext* transparencyLayerContext = context; + + // Ensure our lists are up-to-date. + updateLayerListsIfNeeded(); + +#if ENABLE(CSS_FILTERS) + FilterEffectRendererHelper filterPainter(filterRenderer() && paintsWithFilters()); + if (filterPainter.haveFilterEffect() && !context->paintingDisabled()) { + LayoutPoint rootLayerOffset; + convertToLayerCoords(rootLayer, rootLayerOffset); + RenderLayerFilterInfo* filterInfo = this->filterInfo(); + ASSERT(filterInfo); + LayoutRect filterRepaintRect = filterInfo->dirtySourceRect(); + filterRepaintRect.move(rootLayerOffset.x(), rootLayerOffset.y()); + if (filterPainter.prepareFilterEffect(this, calculateLayerBounds(this, rootLayer, 0), parentPaintDirtyRect, filterRepaintRect)) { + // Now we know for sure, that the source image will be updated, so we can revert our tracking repaint rect back to zero. + filterInfo->resetDirtySourceRect(); + + // Rewire the old context to a memory buffer, so that we can capture the contents of the layer. + // NOTE: We saved the old context in the "transparencyLayerContext" local variable, to be able to start a transparency layer + // on the original context and avoid duplicating "beginFilterEffect" after each transpareny layer call. Also, note that + // beginTransparencyLayers will only create a single lazy transparency layer, even though it is called twice in this method. + context = filterPainter.beginFilterEffect(context); + + // Check that we didn't fail to allocate the graphics context for the offscreen buffer. + if (filterPainter.hasStartedFilterEffect()) { + paintDirtyRect = filterPainter.repaintRect(); + // If the filter needs the full source image, we need to avoid using the clip rectangles. + // Otherwise, if for example this layer has overflow:hidden, a drop shadow will not compute correctly. + // Note that we will still apply the clipping on the final rendering of the filter. + useClipRect = !filterRenderer()->hasFilterThatMovesPixels(); + } + } + } +#endif + if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) { calculateRects(rootLayer, region, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, localPaintFlags & PaintLayerTemporaryClipRects); paintOffset = toPoint(layerBounds.location() - renderBoxLocation()); } - // Ensure our lists are up-to-date. - updateLayerListsIfNeeded(); - bool forceBlackText = paintBehavior & PaintBehaviorForceBlackText; bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly; @@ -2874,10 +3053,6 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co if (overlapTestRequests && isSelfPaintingLayer) performOverlapTests(*overlapTestRequests, rootLayer, this); -#if ENABLE(CSS_FILTERS) - FilterEffectRendererHelper filterPainter(paintsWithFilters()); -#endif - // We want to paint our layer, but only if we intersect the damage rect. shouldPaintContent &= intersectsDamageRect(layerBounds, damageRect.rect(), rootLayer); @@ -2885,23 +3060,22 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co if (shouldPaintContent && !selectionOnly) { // Begin transparency layers lazily now that we know we have to paint something. if (haveTransparency) - beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior); + beginTransparencyLayers(transparencyLayerContext, rootLayer, paintDirtyRect, paintBehavior); -#if ENABLE(CSS_FILTERS) - if (filterPainter.haveFilterEffect() && !context->paintingDisabled()) - context = filterPainter.beginFilterEffect(this, context, paintingExtent(rootLayer, paintDirtyRect, paintBehavior)); -#endif - - // Paint our background first, before painting any child layers. - // Establish the clip used to paint our background. - clipToRect(rootLayer, context, paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self. - + if (useClipRect) { + // Paint our background first, before painting any child layers. + // Establish the clip used to paint our background. + clipToRect(rootLayer, context, paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Background painting will handle clipping to self. + } + // Paint the background. - PaintInfo paintInfo(context, damageRect.rect(), PaintPhaseBlockBackground, false, paintingRootForRenderer, region, 0); + PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseBlockBackground, false, paintingRootForRenderer, region, 0); renderer()->paint(paintInfo, paintOffset); - // Restore the clip. - restoreClip(context, paintDirtyRect, damageRect); + if (useClipRect) { + // Restore the clip. + restoreClip(context, paintDirtyRect, damageRect); + } } // Now walk the sorted list of children with negative z-indices. @@ -2913,16 +3087,14 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co if (shouldPaintContent && !clipRectToApply.isEmpty()) { // Begin transparency layers lazily now that we know we have to paint something. if (haveTransparency) - beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior); + beginTransparencyLayers(transparencyLayerContext, rootLayer, paintDirtyRect, paintBehavior); -#if ENABLE(CSS_FILTERS) - // If the filter was not started yet, start it now, after the transparency layer was lazily created. - if (filterPainter.haveFilterEffect() && !filterPainter.hasStartedFilterEffect() && !context->paintingDisabled()) - context = filterPainter.beginFilterEffect(this, context, paintingExtent(rootLayer, paintDirtyRect, paintBehavior)); -#endif - // Set up the clip used when painting our children. - clipToRect(rootLayer, context, paintDirtyRect, clipRectToApply); - PaintInfo paintInfo(context, clipRectToApply.rect(), + if (useClipRect) { + // Set up the clip used when painting our children. + clipToRect(rootLayer, context, paintDirtyRect, clipRectToApply); + } + + PaintInfo paintInfo(context, pixelSnappedIntRect(clipRectToApply.rect()), selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds, forceBlackText, paintingRootForRenderer, region, 0); renderer()->paint(paintInfo, paintOffset); @@ -2936,13 +3108,15 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co renderer()->paint(paintInfo, paintOffset); } - // Now restore our clip. - restoreClip(context, paintDirtyRect, clipRectToApply); + if (useClipRect) { + // Now restore our clip. + restoreClip(context, paintDirtyRect, clipRectToApply); + } } if (shouldPaintOutline && !outlineRect.isEmpty()) { // Paint our own outline - PaintInfo paintInfo(context, outlineRect.rect(), PaintPhaseSelfOutline, false, paintingRootForRenderer, region, 0); + PaintInfo paintInfo(context, pixelSnappedIntRect(outlineRect.rect()), PaintPhaseSelfOutline, false, paintingRootForRenderer, region, 0); clipToRect(rootLayer, context, paintDirtyRect, outlineRect, DoNotIncludeSelfForBorderRadius); renderer()->paint(paintInfo, paintOffset); restoreClip(context, paintDirtyRect, outlineRect); @@ -2956,14 +3130,17 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co } if ((localPaintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && renderer()->hasMask() && !selectionOnly) { - clipToRect(rootLayer, context, paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self. + if (useClipRect) + clipToRect(rootLayer, context, paintDirtyRect, damageRect, DoNotIncludeSelfForBorderRadius); // Mask painting will handle clipping to self. // Paint the mask. - PaintInfo paintInfo(context, damageRect.rect(), PaintPhaseMask, false, paintingRootForRenderer, region, 0); + PaintInfo paintInfo(context, pixelSnappedIntRect(damageRect.rect()), PaintPhaseMask, false, paintingRootForRenderer, region, 0); renderer()->paint(paintInfo, paintOffset); - // Restore the clip. - restoreClip(context, paintDirtyRect, damageRect); + if (useClipRect) { + // Restore the clip. + restoreClip(context, paintDirtyRect, damageRect); + } } if (isPaintingOverlayScrollbars) { @@ -2973,10 +3150,17 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co } #if ENABLE(CSS_FILTERS) - if (filterPainter.hasStartedFilterEffect()) + if (filterPainter.hasStartedFilterEffect()) { + // Apply the correct clipping (ie. overflow: hidden). + clipToRect(rootLayer, transparencyLayerContext, paintDirtyRect, damageRect); context = filterPainter.applyFilterEffect(); + restoreClip(transparencyLayerContext, paintDirtyRect, damageRect); + } #endif + // Make sure that we now use the original transparency context. + ASSERT(transparencyLayerContext == context); + // End our transparency layer if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) { context->endTransparencyLayer(); @@ -2992,7 +3176,11 @@ void RenderLayer::paintList(Vector<RenderLayer*>* list, RenderLayer* rootLayer, { if (!list) return; - + +#if !ASSERT_DISABLED + LayerListMutationDetector mutationChecker(this); +#endif + for (size_t i = 0; i < list->size(); ++i) { RenderLayer* childLayer = list->at(i); if (!childLayer->isPaginated()) @@ -3132,9 +3320,9 @@ bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result) { renderer()->document()->updateLayout(); - IntRect hitTestArea = renderer()->isRenderFlowThread() ? toRenderFlowThread(renderer())->borderBoxRect() : renderer()->view()->documentRect(); + LayoutRect hitTestArea = renderer()->isRenderFlowThread() ? toRenderFlowThread(renderer())->borderBoxRect() : renderer()->view()->documentRect(); if (!request.ignoreClipping()) - hitTestArea.intersect(pixelSnappedIntRect(frameVisibleRect(renderer()))); + hitTestArea.intersect(frameVisibleRect(renderer())); RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, result.point(), false); if (!insideLayer) { @@ -3377,7 +3565,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. if (fgRect.intersects(hitTestArea) && isSelfPaintingLayer()) { // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost. - HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding()); + HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding(), result.shadowContentFilterPolicy()); if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { if (result.isRectBasedTest()) @@ -3406,7 +3594,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont return candidateLayer; if (bgRect.intersects(hitTestArea) && isSelfPaintingLayer()) { - HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding()); + HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding(), result.shadowContentFilterPolicy()); if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestSelf) && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { if (result.isRectBasedTest()) @@ -3424,7 +3612,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutRect& layerBounds, const LayoutPoint& hitTestPoint, HitTestFilter hitTestFilter) const { if (!renderer()->hitTest(request, result, hitTestPoint, - toPoint(layerBounds.location() - renderBoxLocation()), + toLayoutPoint(layerBounds.location() - renderBoxLocation()), hitTestFilter)) { // It's wrong to set innerNode, but then claim that you didn't hit anything, unless it is // a rect-based test. @@ -3462,7 +3650,7 @@ RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* r for (int i = list->size() - 1; i >= 0; --i) { RenderLayer* childLayer = list->at(i); RenderLayer* hitLayer = 0; - HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding()); + HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding(), result.shadowContentFilterPolicy()); if (childLayer->isPaginated()) hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestPoint, transformState, zOffsetForDescendants); else @@ -3722,8 +3910,11 @@ ClipRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, RenderReg ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, renderer()->style()->position()); RenderView* view = renderer()->view(); ASSERT(view); - if (parentRects.fixed() && rootLayer->renderer() == view) + + // Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite. + if (parentRects.fixed() && rootLayer->renderer() == view && backgroundClipRect != PaintInfo::infiniteRect()) backgroundClipRect.move(view->frameView()->scrollXForFixedPosition(), view->frameView()->scrollYForFixedPosition()); + return backgroundClipRect; } @@ -3804,6 +3995,26 @@ LayoutRect RenderLayer::selfClipRect() const return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect.rect())).enclosingBoundingBox(); } +LayoutRect RenderLayer::localClipRect() const +{ + // FIXME: border-radius not accounted for. + // FIXME: Regions not accounted for. + RenderLayer* clippingRootLayer = clippingRoot(); + LayoutRect layerBounds; + ClipRect backgroundRect, foregroundRect, outlineRect; + calculateRects(clippingRootLayer, 0, PaintInfo::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); + + LayoutRect clipRect = backgroundRect.rect(); + if (clipRect == PaintInfo::infiniteRect()) + return clipRect; + + LayoutPoint clippingRootOffset; + convertToLayerCoords(clippingRootLayer, clippingRootOffset); + clipRect.moveBy(-clippingRootOffset); + + return clipRect; +} + void RenderLayer::addBlockSelectionGapsBounds(const LayoutRect& bounds) { m_blockSelectionGapsBounds.unite(bounds); @@ -3919,9 +4130,116 @@ LayoutRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer) const return result; } -LayoutRect RenderLayer::absoluteBoundingBox() const +IntRect RenderLayer::absoluteBoundingBox() const { - return boundingBox(root()); + return pixelSnappedIntRect(boundingBox(root())); +} + +IntRect RenderLayer::calculateLayerBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer, CalculateLayerBoundsFlags flags) +{ + if (!layer->isSelfPaintingLayer()) + return IntRect(); + + LayoutRect boundingBoxRect = layer->localBoundingBox(); + if (layer->renderer()->isRoot()) { + // If the root layer becomes composited (e.g. because some descendant with negative z-index is composited), + // then it has to be big enough to cover the viewport in order to display the background. This is akin + // to the code in RenderBox::paintRootBoxFillLayers(). + if (FrameView* frameView = layer->renderer()->view()->frameView()) { + LayoutUnit contentsWidth = frameView->contentsWidth(); + LayoutUnit contentsHeight = frameView->contentsHeight(); + + boundingBoxRect.setWidth(max(boundingBoxRect.width(), contentsWidth - boundingBoxRect.x())); + boundingBoxRect.setHeight(max(boundingBoxRect.height(), contentsHeight - boundingBoxRect.y())); + } + } + + LayoutRect unionBounds = boundingBoxRect; + + if (flags & UseLocalClipRectIfPossible) { + LayoutRect localClipRect = layer->localClipRect(); + if (localClipRect != PaintInfo::infiniteRect()) { + LayoutPoint ancestorRelOffset; + layer->convertToLayerCoords(ancestorLayer, ancestorRelOffset); + localClipRect.moveBy(ancestorRelOffset); + return pixelSnappedIntRect(localClipRect); + } + } + + const_cast<RenderLayer*>(layer)->updateLayerListsIfNeeded(); + + if (RenderLayer* reflection = layer->reflectionLayer()) { + if (!reflection->isComposited()) { + IntRect childUnionBounds = calculateLayerBounds(reflection, layer); + unionBounds.unite(childUnionBounds); + } + } + + ASSERT(layer->isStackingContext() || (!layer->posZOrderList() || !layer->posZOrderList()->size())); + +#if !ASSERT_DISABLED + LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(layer)); +#endif + + if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { + size_t listSize = negZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = negZOrderList->at(i); + if (!curLayer->isComposited()) { + IntRect childUnionBounds = calculateLayerBounds(curLayer, layer); + unionBounds.unite(childUnionBounds); + } + } + } + + if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { + size_t listSize = posZOrderList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = posZOrderList->at(i); + if (!curLayer->isComposited()) { + IntRect childUnionBounds = calculateLayerBounds(curLayer, layer); + unionBounds.unite(childUnionBounds); + } + } + } + + if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { + size_t listSize = normalFlowList->size(); + for (size_t i = 0; i < listSize; ++i) { + RenderLayer* curLayer = normalFlowList->at(i); + if (!curLayer->isComposited()) { + IntRect curAbsBounds = calculateLayerBounds(curLayer, layer); + unionBounds.unite(curAbsBounds); + } + } + } + +#if ENABLE(CSS_FILTERS) + // FIXME: We can optimize the size of the composited layers, by not enlarging + // filtered areas with the outsets if we know that the filter is going to render in hardware. + // https://bugs.webkit.org/show_bug.cgi?id=81239 + if ((flags & IncludeLayerFilterOutsets) && layer->renderer()->style()->hasFilterOutsets()) { + int topOutset; + int rightOutset; + int bottomOutset; + int leftOutset; + layer->renderer()->style()->getFilterOutsets(topOutset, rightOutset, bottomOutset, leftOutset); + unionBounds.move(-leftOutset, -topOutset); + unionBounds.expand(leftOutset + rightOutset, topOutset + bottomOutset); + } +#endif + + if ((flags & IncludeSelfTransform) && layer->paintsWithTransform(PaintBehaviorNormal)) { + TransformationMatrix* affineTrans = layer->transform(); + boundingBoxRect = affineTrans->mapRect(boundingBoxRect); + unionBounds = affineTrans->mapRect(unionBounds); + } + + LayoutPoint ancestorRelOffset; + layer->convertToLayerCoords(ancestorLayer, ancestorRelOffset); + unionBounds.moveBy(ancestorRelOffset); + + return pixelSnappedIntRect(unionBounds); } void RenderLayer::clearClipRectsIncludingDescendants() @@ -3960,16 +4278,18 @@ RenderLayerBacking* RenderLayer::ensureBacking() return m_backing.get(); } -void RenderLayer::clearBacking() +void RenderLayer::clearBacking(bool layerBeingDestroyed) { if (m_backing && !renderer()->documentBeingDestroyed()) compositor()->layerBecameNonComposited(this); m_backing.clear(); #if ENABLE(CSS_FILTERS) - updateOrRemoveFilterEffect(); + if (!layerBeingDestroyed) + updateOrRemoveFilterEffect(); +#else + UNUSED_PARAM(layerBeingDestroyed); #endif - } bool RenderLayer::hasCompositedMask() const @@ -3996,7 +4316,7 @@ GraphicsLayer* RenderLayer::layerForScrollCorner() const bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const { #if USE(ACCELERATED_COMPOSITING) - bool paintsToWindow = !isComposited() || backing()->paintingGoesToWindow(); + bool paintsToWindow = !isComposited() || backing()->paintsIntoWindow(); #else bool paintsToWindow = true; #endif @@ -4141,6 +4461,10 @@ static inline bool compareZIndex(RenderLayer* first, RenderLayer* second) void RenderLayer::dirtyZOrderLists() { + ASSERT(m_layerListMutationAllowed); + // We cannot assume that we are called on a stacking context as it + // is called when we just got demoted from being a stacking context. + if (m_posZOrderList) m_posZOrderList->clear(); if (m_negZOrderList) @@ -4162,6 +4486,8 @@ void RenderLayer::dirtyStackingContextZOrderLists() void RenderLayer::dirtyNormalFlowList() { + ASSERT(m_layerListMutationAllowed); + if (m_normalFlowList) m_normalFlowList->clear(); m_normalFlowListDirty = true; @@ -4172,8 +4498,11 @@ void RenderLayer::dirtyNormalFlowList() #endif } -void RenderLayer::updateZOrderListsSlowCase() +void RenderLayer::rebuildZOrderLists() { + ASSERT(m_layerListMutationAllowed); + ASSERT(isDirtyStackingContext()); + #if USE(ACCELERATED_COMPOSITING) bool includeHiddenLayers = compositor()->inCompositingMode(); #else @@ -4197,7 +4526,9 @@ void RenderLayer::updateNormalFlowList() { if (!m_normalFlowListDirty) return; - + + ASSERT(m_layerListMutationAllowed); + for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { // Ignore non-overflow layers and reflections. if (child->isNormalFlowOnly() && (!m_reflection || reflectionLayer() != child)) { @@ -4243,13 +4574,18 @@ void RenderLayer::updateLayerListsIfNeeded() { updateZOrderLists(); updateNormalFlowList(); + + if (RenderLayer* reflectionLayer = this->reflectionLayer()) { + reflectionLayer->updateZOrderLists(); + reflectionLayer->updateNormalFlowList(); + } } void RenderLayer::updateCompositingAndLayerListsIfNeeded() { #if USE(ACCELERATED_COMPOSITING) if (compositor()->inCompositingMode()) { - if ((isStackingContext() && m_zOrderListsDirty) || m_normalFlowListDirty) + if (isDirtyStackingContext() || m_normalFlowListDirty) compositor()->updateCompositingLayers(CompositingUpdateOnHitTest, this); return; } @@ -4268,7 +4604,7 @@ void RenderLayer::repaintIncludingDescendants() void RenderLayer::setBackingNeedsRepaint() { ASSERT(isComposited()); - if (backing()->paintingGoesToWindow()) { + if (backing()->paintsIntoWindow()) { // If we're trying to repaint the placeholder document layer, propagate the // repaint to the native view system. RenderView* view = renderer()->view(); @@ -4283,7 +4619,7 @@ void RenderLayer::setBackingNeedsRepaintInRect(const LayoutRect& r) // https://bugs.webkit.org/show_bug.cgi?id=61159 describes an unreproducible crash here, // so assert but check that the layer is composited. ASSERT(isComposited()); - if (!isComposited() || backing()->paintingGoesToWindow()) { + if (!isComposited() || backing()->paintsIntoWindow()) { // If we're trying to repaint the placeholder document layer, propagate the // repaint to the native view system. LayoutRect absRect(r); @@ -4343,6 +4679,40 @@ bool RenderLayer::isSelfPaintingLayer() const || renderer()->isRenderIFrame(); } +static bool overflowCanHaveAScrollbar(EOverflow overflow) +{ + return overflow == OAUTO || overflow == OSCROLL || overflow == OOVERLAY; +} + +void RenderLayer::updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle) +{ + // Overflow are a box concept. + if (!renderBox()) + return; + + EOverflow overflowX = renderBox()->style()->overflowX(); + EOverflow overflowY = renderBox()->style()->overflowY(); + if (hasHorizontalScrollbar() && !overflowCanHaveAScrollbar(overflowX)) + setHasHorizontalScrollbar(false); + if (hasVerticalScrollbar() && !overflowCanHaveAScrollbar(overflowY)) + setHasVerticalScrollbar(false); + + // With overflow: scroll, scrollbars are always visible but may be disabled. + // When switching to another value, we need to re-enable them (see bug 11985). + if (hasHorizontalScrollbar() && oldStyle->overflowX() == OSCROLL && overflowX != OSCROLL) { + ASSERT(overflowCanHaveAScrollbar(overflowX)); + m_hBar->setEnabled(true); + } + + if (hasVerticalScrollbar() && oldStyle->overflowY() == OSCROLL && overflowY != OSCROLL) { + ASSERT(overflowCanHaveAScrollbar(overflowY)); + m_vBar->setEnabled(true); + } + + if (!m_scrollDimensionsDirty) + updateScrollableAreaSet((hasHorizontalOverflow() || hasVerticalOverflow()) && scrollsOverflow()); +} + void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle) { bool isNormalFlowOnly = shouldBeNormalFlowOnly(); @@ -4364,6 +4734,8 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle) m_marquee = 0; } + updateScrollbarsAfterStyleChange(oldStyle); + if (!hasReflection() && m_reflection) removeReflection(); else if (hasReflection()) { @@ -4372,19 +4744,6 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle) updateReflectionStyle(); } -#if ENABLE(CSS_FILTERS) - updateOrRemoveFilterEffect(); -#endif - - if (Frame* frame = renderer()->frame()) { - if (FrameView* frameView = frame->view()) { - if (scrollsOverflow()) - frameView->addScrollableArea(this); - else - frameView->removeScrollableArea(this); - } - } - // FIXME: Need to detect a swap from custom to native scrollbars (and vice versa). if (m_hBar) m_hBar->styleChanged(); @@ -4394,11 +4753,18 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle) updateScrollCornerStyle(); updateResizerStyle(); +#if ENABLE(CSS_FILTERS) + bool backingDidCompositeLayers = isComposited() && backing()->canCompositeFilters(); +#endif + #if USE(ACCELERATED_COMPOSITING) + updateVisibilityStatus(); updateTransform(); if (compositor()->updateLayerCompositingState(this)) compositor()->setCompositingLayersNeedRebuild(); + else if (oldStyle && (oldStyle->clip() != renderer()->style()->clip() || oldStyle->hasClip() != renderer()->style()->hasClip())) + compositor()->setCompositingLayersNeedRebuild(); else if (m_backing) m_backing->updateGraphicsLayerGeometry(); else if (oldStyle && oldStyle->overflowX() != renderer()->style()->overflowX()) { @@ -4406,6 +4772,35 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle) compositor()->setCompositingLayersNeedRebuild(); } #endif + +#if ENABLE(CSS_FILTERS) + updateOrRemoveFilterEffect(); + if (isComposited() && backingDidCompositeLayers && !backing()->canCompositeFilters()) { + // The filters used to be drawn by platform code, but now the platform cannot draw them anymore. + // Fallback to drawing them in software. + setBackingNeedsRepaint(); + } +#endif +} + +void RenderLayer::updateScrollableAreaSet(bool hasOverflow) +{ + Frame* frame = renderer()->frame(); + if (!frame) + return; + + FrameView* frameView = frame->view(); + if (!frameView) + return; + + bool isVisibleToHitTest = renderer()->visibleToHitTesting(); + if (HTMLFrameOwnerElement* owner = frame->ownerElement()) + isVisibleToHitTest &= owner->renderer() && owner->renderer()->visibleToHitTesting(); + + if (hasOverflow && isVisibleToHitTest) + frameView->addScrollableArea(this); + else + frameView->removeScrollableArea(this); } void RenderLayer::updateScrollCornerStyle() @@ -4502,17 +4897,38 @@ void RenderLayer::updateReflectionStyle() #if ENABLE(CSS_FILTERS) void RenderLayer::updateOrRemoveFilterEffect() { - if (paintsWithFilters()) { - if (!m_filter) { - m_filter = FilterEffectRenderer::create(this); - RenderingMode renderingMode = renderer()->frame()->page()->settings()->acceleratedFiltersEnabled() ? Accelerated : Unaccelerated; - m_filter->setRenderingMode(renderingMode); - } + if (!hasFilter()) { + removeFilterInfoIfNeeded(); + return; + } - m_filter->build(renderer()->document(), renderer()->style()->filter()); - } else { - m_filter = 0; +#if ENABLE(CSS_SHADERS) + if (renderer()->style()->filter().hasCustomFilter()) + ensureFilterInfo()->updateCustomFilterClients(renderer()->style()->filter()); + else if (hasFilterInfo()) + filterInfo()->removeCustomFilterClients(); +#endif + + if (!paintsWithFilters()) { + // Don't delete the whole filter info here, because we might use it + // for loading CSS shader files. + if (RenderLayerFilterInfo* filterInfo = this->filterInfo()) + filterInfo->setRenderer(0); + return; } + + RenderLayerFilterInfo* filterInfo = ensureFilterInfo(); + if (!filterInfo->renderer()) { + RefPtr<FilterEffectRenderer> filterRenderer = FilterEffectRenderer::create(); + RenderingMode renderingMode = renderer()->frame()->page()->settings()->acceleratedFiltersEnabled() ? Accelerated : Unaccelerated; + filterRenderer->setRenderingMode(renderingMode); + filterInfo->setRenderer(filterRenderer.release()); + } + + // If the filter fails to build, remove it from the layer. It will still attempt to + // go through regular processing (e.g. compositing), but never apply anything. + if (!filterInfo->renderer()->build(renderer()->document(), renderer()->style()->filter())) + filterInfo->setRenderer(0); } void RenderLayer::filterNeedsRepaint() diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h index 4f5ec91f1..95c0f3933 100644 --- a/Source/WebCore/rendering/RenderLayer.h +++ b/Source/WebCore/rendering/RenderLayer.h @@ -44,15 +44,15 @@ #ifndef RenderLayer_h #define RenderLayer_h -#if ENABLE(CSS_FILTERS) -#include "FilterEffectObserver.h" -#endif #include "PaintInfo.h" #include "RenderBox.h" -#include "ScrollBehavior.h" #include "ScrollableArea.h" #include <wtf/OwnPtr.h> +#if ENABLE(CSS_FILTERS) +#include "RenderLayerFilterInfo.h" +#endif + namespace WebCore { #if ENABLE(CSS_FILTERS) @@ -100,6 +100,8 @@ public: void setHasRadius(bool hasRadius) { m_hasRadius = hasRadius; } bool operator==(const ClipRect& other) const { return rect() == other.rect() && hasRadius() == other.hasRadius(); } + bool operator!=(const ClipRect& other) const { return rect() != other.rect() || hasRadius() != other.hasRadius(); } + bool operator!=(const LayoutRect& otherRect) const { return rect() != otherRect; } void intersect(const LayoutRect& other) { m_rect.intersect(other); } void intersect(const ClipRect& other) @@ -211,11 +213,7 @@ private: bool m_fixed : 1; }; -class RenderLayer : public ScrollableArea -#if ENABLE(CSS_FILTERS) - , public FilterEffectObserver -#endif -{ +class RenderLayer : public ScrollableArea { public: friend class RenderReplica; @@ -280,8 +278,8 @@ public: LayoutRect rect() const { return LayoutRect(location(), size()); } - int scrollWidth(); - int scrollHeight(); + int scrollWidth() const; + int scrollHeight() const; void panScrollFromPoint(const LayoutPoint&); @@ -301,7 +299,7 @@ public: void scrollToXOffset(int x, ScrollOffsetClamping clamp = ScrollOffsetUnclamped) { scrollToOffset(x, scrollYOffset(), clamp); } void scrollToYOffset(int y, ScrollOffsetClamping clamp = ScrollOffsetUnclamped) { scrollToOffset(scrollXOffset(), y, clamp); } - void scrollRectToVisible(const LayoutRect&, const ScrollAlignment& alignX = ScrollAlignment::alignCenterIfNeeded, const ScrollAlignment& alignY = ScrollAlignment::alignCenterIfNeeded); + void scrollRectToVisible(const LayoutRect&, const ScrollAlignment& alignX, const ScrollAlignment& alignY); LayoutRect getRectToExpose(const LayoutRect& visibleRect, const LayoutRect& exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY); @@ -314,6 +312,9 @@ public: PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation); void destroyScrollbar(ScrollbarOrientation); + bool hasHorizontalScrollbar() const { return horizontalScrollbar(); } + bool hasVerticalScrollbar() const { return verticalScrollbar(); } + // ScrollableArea overrides virtual Scrollbar* horizontalScrollbar() const { return m_hBar.get(); } virtual Scrollbar* verticalScrollbar() const { return m_vBar.get(); } @@ -347,13 +348,9 @@ public: // Notification from the renderer that its content changed (e.g. current frame of image changed). // Allows updates of layer content without repainting. - enum ContentChangeType { ImageChanged, MaskImageChanged, CanvasChanged, VideoChanged, FullScreenChanged }; void contentChanged(ContentChangeType); #endif - // Returns true if the accelerated compositing is enabled - bool hasAcceleratedCompositing() const; - bool canRender3DTransforms() const; void updateLayerPosition(); @@ -389,13 +386,26 @@ public: void dirtyZOrderLists(); void dirtyStackingContextZOrderLists(); - void updateZOrderLists(); - Vector<RenderLayer*>* posZOrderList() const { return m_posZOrderList; } - Vector<RenderLayer*>* negZOrderList() const { return m_negZOrderList; } + + Vector<RenderLayer*>* posZOrderList() const + { + ASSERT(!m_zOrderListsDirty); + ASSERT(isStackingContext() || !m_posZOrderList); + return m_posZOrderList; + } + + Vector<RenderLayer*>* negZOrderList() const + { + ASSERT(!m_zOrderListsDirty); + ASSERT(isStackingContext() || !m_negZOrderList); + return m_negZOrderList; + } void dirtyNormalFlowList(); - void updateNormalFlowList(); - Vector<RenderLayer*>* normalFlowList() const { return m_normalFlowList; } + Vector<RenderLayer*>* normalFlowList() const { ASSERT(!m_normalFlowListDirty); return m_normalFlowList; } + + // Update our normal and z-index lists. + void updateLayerListsIfNeeded(); // FIXME: We should ASSERT(!m_visibleContentStatusDirty) here, but see https://bugs.webkit.org/show_bug.cgi?id=71044 // ditto for hasVisibleDescendant(), see https://bugs.webkit.org/show_bug.cgi?id=71277 @@ -417,10 +427,17 @@ public: #if USE(ACCELERATED_COMPOSITING) // Enclosing compositing layer; if includeSelf is true, may return this. RenderLayer* enclosingCompositingLayer(bool includeSelf = true) const; + RenderLayer* enclosingCompositingLayerForRepaint(bool includeSelf = true) const; // Ancestor compositing layer, excluding this. RenderLayer* ancestorCompositingLayer() const { return enclosingCompositingLayer(false); } #endif +#if ENABLE(CSS_FILTERS) + RenderLayer* enclosingFilterLayer(bool includeSelf = true) const; + RenderLayer* enclosingFilterRepaintLayer() const; + void setFilterBackendNeedsRepaintingInRect(const LayoutRect&, bool immediate); +#endif + void convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntPoint& location) const; void convertToPixelSnappedLayerCoords(const RenderLayer* ancestorLayer, IntRect&) const; void convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutPoint& location) const; @@ -468,6 +485,7 @@ public: LayoutRect childrenClipRect() const; // Returns the foreground clip rect of the layer in the document's coordinate space. LayoutRect selfClipRect() const; // Returns the background clip rect of the layer in the document's coordinate space. + LayoutRect localClipRect() const; // Returns the background clip rect of the layer in the local coordinate space. bool intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer) const; @@ -475,9 +493,18 @@ public: LayoutRect boundingBox(const RenderLayer* rootLayer) const; // Bounding box in the coordinates of this layer. LayoutRect localBoundingBox() const; - // Bounding box relative to the root. - LayoutRect absoluteBoundingBox() const; - + // Pixel snapped bounding box relative to the root. + IntRect absoluteBoundingBox() const; + + enum CalculateLayerBoundsFlag { + IncludeSelfTransform = 1 << 0, + UseLocalClipRectIfPossible = 1 << 1, + IncludeLayerFilterOutsets = 1 << 2, + DefaultCalculateLayerBoundsFlags = IncludeSelfTransform | UseLocalClipRectIfPossible | IncludeLayerFilterOutsets + }; + typedef unsigned CalculateLayerBoundsFlags; + static IntRect calculateLayerBounds(const RenderLayer*, const RenderLayer* ancestorLayer, CalculateLayerBoundsFlags = DefaultCalculateLayerBoundsFlags); + void updateHoverActiveState(const HitTestRequest&, HitTestResult&); // WARNING: This method returns the offset for the parent as this is what updateLayerPositions expects. @@ -539,7 +566,7 @@ public: bool hasCompositedMask() const; RenderLayerBacking* backing() const { return m_backing.get(); } RenderLayerBacking* ensureBacking(); - void clearBacking(); + void clearBacking(bool layerBeingDestroyed = false); virtual GraphicsLayer* layerForHorizontalScrollbar() const; virtual GraphicsLayer* layerForVerticalScrollbar() const; virtual GraphicsLayer* layerForScrollCorner() const; @@ -560,11 +587,38 @@ public: #if ENABLE(CSS_FILTERS) bool paintsWithFilters() const; - FilterEffectRenderer* filter() const { return m_filter.get(); } + bool requiresFullLayerImageForFilters() const; + FilterEffectRenderer* filterRenderer() const + { + RenderLayerFilterInfo* filterInfo = this->filterInfo(); + return filterInfo ? filterInfo->renderer() : 0; + } + + RenderLayerFilterInfo* filterInfo() const { return hasFilterInfo() ? RenderLayerFilterInfo::filterInfoForRenderLayer(this) : 0; } + RenderLayerFilterInfo* ensureFilterInfo() { return RenderLayerFilterInfo::createFilterInfoForRenderLayerIfNeeded(this); } + void removeFilterInfoIfNeeded() + { + if (hasFilterInfo()) + RenderLayerFilterInfo::removeFilterInfoForRenderLayer(this); + } + + bool hasFilterInfo() const { return m_hasFilterInfo; } + void setHasFilterInfo(bool hasFilterInfo) { m_hasFilterInfo = hasFilterInfo; } +#endif + +#if !ASSERT_DISABLED + bool layerListMutationAllowed() const { return m_layerListMutationAllowed; } + void setLayerListMutationAllowed(bool flag) { m_layerListMutationAllowed = flag; } #endif private: - void updateZOrderListsSlowCase(); + void updateZOrderLists(); + void rebuildZOrderLists(); + void clearZOrderLists(); + + void updateNormalFlowList(); + + bool isDirtyStackingContext() const { return m_zOrderListsDirty && isStackingContext(); } void computeRepaintRects(LayoutPoint* offsetFromRoot = 0); void clearRepaintRects(); @@ -575,6 +629,9 @@ private: bool shouldRepaintAfterLayout() const; + void updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle); + void updateScrollbarsAfterLayout(); + friend IntSize RenderBox::scrolledContentOffset() const; IntSize scrolledContentOffset() const { return scrollOffset() + m_scrollOverflow; } @@ -593,7 +650,6 @@ private: void collectLayers(bool includeHiddenLayers, Vector<RenderLayer*>*&, Vector<RenderLayer*>*&); - void updateLayerListsIfNeeded(); void updateCompositingAndLayerListsIfNeeded(); void paintLayer(RenderLayer* rootLayer, GraphicsContext*, const LayoutRect& paintDirtyRect, @@ -639,7 +695,9 @@ private: bool hitTestContents(const HitTestRequest&, HitTestResult&, const LayoutRect& layerBounds, const LayoutPoint& hitTestPoint, HitTestFilter) const; - void computeScrollDimensions(bool* needHBar = 0, bool* needVBar = 0); + void computeScrollDimensions(); + bool hasHorizontalOverflow() const; + bool hasVerticalOverflow() const; bool shouldBeNormalFlowOnly() const; @@ -675,9 +733,12 @@ private: // NOTE: This should only be called by the overriden setScrollOffset from ScrollableArea. void scrollTo(int, int); + void updateCompositingLayersAfterScroll(); IntSize scrollbarOffset(const Scrollbar*) const; + void updateScrollableAreaSet(bool hasOverflow); + void childVisibilityChanged(bool newVisibility); void dirtyVisibleDescendantStatus(); void updateVisibilityStatus(); @@ -788,12 +849,18 @@ protected: #endif bool m_containsDirtyOverlayScrollbars : 1; - +#if !ASSERT_DISABLED + bool m_layerListMutationAllowed : 1; +#endif // This is an optimization added for <table>. // Currently cells do not need to update their repaint rectangles when scrolling. This also // saves a lot of time when scrolling on a table. bool m_canSkipRepaintRectsUpdateOnScroll : 1; +#if ENABLE(CSS_FILTERS) + bool m_hasFilterInfo : 1; +#endif + RenderBoxModelObject* m_renderer; RenderLayer* m_parent; @@ -854,10 +921,6 @@ protected: // May ultimately be extended to many replicas (with their own paint order). RenderReplica* m_reflection; - -#if ENABLE(CSS_FILTERS) - RefPtr<FilterEffectRenderer> m_filter; -#endif // Renderers to hold our custom scroll corner and resizer. RenderScrollbarPart* m_scrollCorner; @@ -871,13 +934,55 @@ private: #endif }; +inline void RenderLayer::clearZOrderLists() +{ + if (m_posZOrderList) { + delete m_posZOrderList; + m_posZOrderList = 0; + } + + if (m_negZOrderList) { + delete m_negZOrderList; + m_negZOrderList = 0; + } +} + inline void RenderLayer::updateZOrderLists() { - if (!m_zOrderListsDirty || !isStackingContext()) + if (!m_zOrderListsDirty) + return; + + if (!isStackingContext()) { + clearZOrderLists(); + m_zOrderListsDirty = false; return; - updateZOrderListsSlowCase(); + } + + rebuildZOrderLists(); } +#if !ASSERT_DISABLED +class LayerListMutationDetector { +public: + LayerListMutationDetector(RenderLayer* layer) + : m_layer(layer) + , m_previousMutationAllowedState(layer->layerListMutationAllowed()) + { + m_layer->setLayerListMutationAllowed(false); + } + + ~LayerListMutationDetector() + { + m_layer->setLayerListMutationAllowed(m_previousMutationAllowedState); + } + +private: + RenderLayer* m_layer; + bool m_previousMutationAllowedState; +}; +#endif + + } // namespace WebCore #ifndef NDEBUG diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp index daed5c265..10a16aff2 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.cpp +++ b/Source/WebCore/rendering/RenderLayerBacking.cpp @@ -32,7 +32,6 @@ #include "AnimationController.h" #include "CanvasRenderingContext.h" #include "CSSPropertyNames.h" -#include "CSSStyleSelector.h" #include "Chrome.h" #include "FontCache.h" #include "FrameView.h" @@ -52,6 +51,8 @@ #include "RenderEmbeddedObject.h" #include "RenderVideo.h" #include "RenderView.h" +#include "StyleResolver.h" +#include "TiledBacking.h" #if ENABLE(CSS_FILTERS) #include "FilterEffectRenderer.h" @@ -91,6 +92,7 @@ RenderLayerBacking::RenderLayerBacking(RenderLayer* layer) , m_artificiallyInflatedBounds(false) , m_isMainFrameRenderViewLayer(false) , m_usingTiledCacheLayer(false) + , m_requiresOwnBackingStore(true) #if ENABLE(CSS_FILTERS) , m_canCompositeFilters(false) #endif @@ -110,6 +112,15 @@ RenderLayerBacking::RenderLayerBacking(RenderLayer* layer) } createPrimaryGraphicsLayer(); + + if (m_usingTiledCacheLayer) { + if (Page* page = renderer()->frame()->page()) { + if (TiledBacking* tiledBacking = m_graphicsLayer->tiledBacking()) { + tiledBacking->setIsInWindow(page->isOnscreen()); + tiledBacking->setCanHaveScrollbars(renderer()->frame()->view()->canHaveScrollbars()); + } + } + } } RenderLayerBacking::~RenderLayerBacking() @@ -130,6 +141,11 @@ PassOwnPtr<GraphicsLayer> RenderLayerBacking::createGraphicsLayer(const String& UNUSED_PARAM(name); #endif graphicsLayer->setMaintainsPixelAlignment(compositor()->keepLayersPixelAligned()); + +#if PLATFORM(MAC) && USE(CA) + graphicsLayer->setAcceleratesDrawing(compositor()->acceleratedDrawingEnabled()); +#endif + return graphicsLayer.release(); } @@ -150,6 +166,14 @@ void RenderLayerBacking::createPrimaryGraphicsLayer() m_graphicsLayer->setContentsOpaque(true); m_graphicsLayer->setAppliesPageScale(); } + +#if PLATFORM(MAC) && USE(CA) + if (!compositor()->acceleratedDrawingEnabled() && renderer()->isCanvas()) { + HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(renderer()->node()); + if (canvas->shouldAccelerate(canvas->size())) + m_graphicsLayer->setAcceleratesDrawing(true); + } +#endif updateLayerOpacity(renderer()->style()); updateLayerTransform(renderer()->style()); @@ -481,7 +505,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() } if (m_owningLayer->hasTransform()) { - const IntRect borderBox = pixelSnappedIntRect(toRenderBox(renderer())->borderBoxRect()); + const IntRect borderBox = toRenderBox(renderer())->pixelSnappedBorderBoxRect(); // Get layout bounds in the coords of compAncestor to match relativeCompositingBounds. IntRect layerBounds = IntRect(delta, borderBox.size()); @@ -542,6 +566,10 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() } m_graphicsLayer->setContentsRect(contentsBox()); + + // If this layer was created just for clipping or to apply perspective, it doesn't need its own backing store. + setRequiresOwnBackingStore(compositor()->requiresOwnBackingStore(m_owningLayer, compAncestor)); + updateDrawsContent(); updateAfterWidgetResize(); } @@ -580,7 +608,12 @@ void RenderLayerBacking::updateInternalHierarchy() void RenderLayerBacking::updateDrawsContent() { - m_graphicsLayer->setDrawsContent(containsPaintedContent()); + bool hasPaintedContent = containsPaintedContent(); + + // FIXME: we could refine this to only allocate backing for one of these layers if possible. + m_graphicsLayer->setDrawsContent(hasPaintedContent); + if (m_foregroundLayer) + m_foregroundLayer->setDrawsContent(hasPaintedContent); } // Return true if the layers changed. @@ -786,6 +819,31 @@ void RenderLayerBacking::updateBackgroundColor() m_graphicsLayer->setContentsToBackgroundColor(rendererBackgroundColor()); } +bool RenderLayerBacking::paintsBoxDecorations() const +{ + if (!m_owningLayer->hasVisibleContent()) + return false; + + if (hasBoxDecorationsOrBackground(renderer())) + return true; + + if (m_owningLayer->hasOverflowControls()) + return true; + + return false; +} + +bool RenderLayerBacking::paintsChildren() const +{ + if (m_owningLayer->hasVisibleContent() && containsNonEmptyRenderers()) + return true; + + if (hasVisibleNonCompositingDescendantLayers()) + return true; + + return false; +} + // A "simple container layer" is a RenderLayer which has no visible content to render. // It may have no children, or all its children may be themselves composited. // This is a useful optimization, because it allows us to avoid allocating backing store. @@ -796,29 +854,16 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const renderObject->hasMask()) // masks require special treatment return false; - RenderStyle* style = renderObject->style(); - bool isVisible = m_owningLayer->hasVisibleContent(); - - // Reject anything that has a border, a border-radius or outline, - // or any background (color or image). - // FIXME: we could optimize layers for simple backgrounds. - if (isVisible && hasBoxDecorationsOrBackground(renderObject)) - return false; - - if (isVisible && m_owningLayer->hasOverflowControls()) + if (paintsBoxDecorations() || paintsChildren()) return false; - - // If we have got this far and the renderer has no children, then we're ok. - if (!renderObject->firstChild()) - return true; if (renderObject->node() && renderObject->node()->isDocumentNode()) { // Look to see if the root object has a non-simple background - RenderObject* rootObject = renderObject->document()->documentElement()->renderer(); + RenderObject* rootObject = renderObject->document()->documentElement() ? renderObject->document()->documentElement()->renderer() : 0; if (!rootObject) return false; - style = rootObject->style(); + RenderStyle* style = rootObject->style(); // Reject anything that has a border, a border-radius or outline, // or is not a simple background (no background, or solid color). @@ -837,13 +882,6 @@ bool RenderLayerBacking::isSimpleContainerCompositingLayer() const return false; } - // Check to see if all the renderer's children are compositing layers. - if (isVisible && containsNonEmptyRenderers()) - return false; - - if (hasVisibleNonCompositingDescendantLayers()) - return false; - return true; } @@ -869,6 +907,13 @@ bool RenderLayerBacking::containsNonEmptyRenderers() const // Conservative test for having no rendered children. bool RenderLayerBacking::hasVisibleNonCompositingDescendantLayers() const { + // FIXME: We shouldn't be called with a stale z-order lists. See bug 85512. + m_owningLayer->updateLayerListsIfNeeded(); + +#if !ASSERT_DISABLED + LayerListMutationDetector mutationChecker(m_owningLayer); +#endif + if (Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList()) { size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) { @@ -907,7 +952,7 @@ bool RenderLayerBacking::hasVisibleNonCompositingDescendantLayers() const bool RenderLayerBacking::containsPaintedContent() const { - if (isSimpleContainerCompositingLayer() || paintingGoesToWindow() || m_artificiallyInflatedBounds || m_owningLayer->isReflection()) + if (isSimpleContainerCompositingLayer() || paintsIntoWindow() || paintsIntoCompositedAncestor() || m_artificiallyInflatedBounds || m_owningLayer->isReflection()) return false; if (isDirectlyCompositedImage()) @@ -946,14 +991,14 @@ bool RenderLayerBacking::isDirectlyCompositedImage() const return false; } -void RenderLayerBacking::contentChanged(RenderLayer::ContentChangeType changeType) +void RenderLayerBacking::contentChanged(ContentChangeType changeType) { - if ((changeType == RenderLayer::ImageChanged) && isDirectlyCompositedImage()) { + if ((changeType == ImageChanged) && isDirectlyCompositedImage()) { updateImageContents(); return; } - if ((changeType == RenderLayer::MaskImageChanged) && m_maskLayer) { + if ((changeType == MaskImageChanged) && m_maskLayer) { // The composited layer bounds relies on box->maskClipRect(), which changes // when the mask image becomes available. bool isUpdateRoot = true; @@ -961,7 +1006,7 @@ void RenderLayerBacking::contentChanged(RenderLayer::ContentChangeType changeTyp } #if ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS) - if ((changeType == RenderLayer::CanvasChanged) && isAcceleratedCanvas(renderer())) { + if ((changeType == CanvasChanged) && isAcceleratedCanvas(renderer())) { m_graphicsLayer->setContentsNeedsDisplay(); return; } @@ -1000,8 +1045,8 @@ FloatPoint3D RenderLayerBacking::computeTransformOrigin(const IntRect& borderBox RenderStyle* style = renderer()->style(); FloatPoint3D origin; - origin.setX(style->transformOriginX().calcFloatValue(borderBox.width())); - origin.setY(style->transformOriginY().calcFloatValue(borderBox.height())); + origin.setX(floatValueForLength(style->transformOriginX(), borderBox.width())); + origin.setY(floatValueForLength(style->transformOriginY(), borderBox.height())); origin.setZ(style->transformOriginZ()); return origin; @@ -1015,8 +1060,8 @@ FloatPoint RenderLayerBacking::computePerspectiveOrigin(const IntRect& borderBox float boxHeight = borderBox.height(); FloatPoint origin; - origin.setX(style->perspectiveOriginX().calcFloatValue(boxWidth)); - origin.setY(style->perspectiveOriginY().calcFloatValue(boxHeight)); + origin.setX(floatValueForLength(style->perspectiveOriginX(), boxWidth)); + origin.setY(floatValueForLength(style->perspectiveOriginY(), boxHeight)); return origin; } @@ -1046,19 +1091,27 @@ IntRect RenderLayerBacking::contentsBox() const return contentsRect; } -bool RenderLayerBacking::paintingGoesToWindow() const +bool RenderLayerBacking::paintsIntoWindow() const { if (m_usingTiledCacheLayer) return false; - if (m_owningLayer->isRootLayer()) + if (m_owningLayer->isRootLayer()) { +#if PLATFORM(BLACKBERRY) + if (compositor()->inForcedCompositingMode()) + return false; +#endif + return compositor()->rootLayerAttachment() != RenderLayerCompositor::RootLayerAttachedViaEnclosingFrame; + } return false; } void RenderLayerBacking::setContentsNeedDisplay() { + ASSERT(!paintsIntoCompositedAncestor()); + if (m_graphicsLayer && m_graphicsLayer->drawsContent()) m_graphicsLayer->setNeedsDisplay(); @@ -1072,6 +1125,8 @@ void RenderLayerBacking::setContentsNeedDisplay() // r is in the coordinate space of the layer's render object void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r) { + ASSERT(!paintsIntoCompositedAncestor()); + if (m_graphicsLayer && m_graphicsLayer->drawsContent()) { IntRect layerDirtyRect = r; layerDirtyRect.move(-m_graphicsLayer->offsetFromRenderer()); @@ -1096,7 +1151,7 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* PaintBehavior paintBehavior, GraphicsLayerPaintingPhase paintingPhase, RenderObject* paintingRoot) { - if (paintingGoesToWindow()) { + if (paintsIntoWindow() || paintsIntoCompositedAncestor()) { ASSERT_NOT_REACHED(); return; } @@ -1134,6 +1189,10 @@ static void paintScrollbar(Scrollbar* scrollbar, GraphicsContext& context, const // Up-call from compositing layer drawing callback. void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip) { +#ifndef NDEBUG + if (Page* page = renderer()->frame()->page()) + page->setIsPainting(true); +#endif if (graphicsLayer == m_graphicsLayer.get() || graphicsLayer == m_foregroundLayer.get() || graphicsLayer == m_maskLayer.get()) { InspectorInstrumentationCookie cookie = InspectorInstrumentation::willPaint(m_owningLayer->renderer()->frame(), &context, clip); @@ -1159,6 +1218,10 @@ void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, Graph m_owningLayer->paintResizer(&context, IntPoint(), transformedClip); context.restore(); } +#ifndef NDEBUG + if (Page* page = renderer()->frame()->page()) + page->setIsPainting(false); +#endif } float RenderLayerBacking::pageScaleFactor() const @@ -1186,6 +1249,13 @@ bool RenderLayerBacking::showRepaintCounter(const GraphicsLayer*) const return compositor() ? compositor()->compositorShowRepaintCounter() : false; } +#ifndef NDEBUG +void RenderLayerBacking::verifyNotPainting() +{ + ASSERT(!renderer()->frame()->page() || !renderer()->frame()->page()->isPainting()); +} +#endif + bool RenderLayerBacking::startAnimation(double timeOffset, const Animation* anim, const KeyframeList& keyframes) { bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity); @@ -1236,21 +1306,15 @@ bool RenderLayerBacking::startAnimation(double timeOffset, const Animation* anim bool didAnimateFilter = false; #endif - if (hasTransform && m_graphicsLayer->addAnimation(transformVector, pixelSnappedIntRect(toRenderBox(renderer())->borderBoxRect()).size(), anim, keyframes.animationName(), timeOffset)) { + if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->pixelSnappedBorderBoxRect().size(), anim, keyframes.animationName(), timeOffset)) didAnimateTransform = true; - compositor()->didStartAcceleratedAnimation(CSSPropertyWebkitTransform); - } - if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), timeOffset)) { + if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), timeOffset)) didAnimateOpacity = true; - compositor()->didStartAcceleratedAnimation(CSSPropertyOpacity); - } #if ENABLE(CSS_FILTERS) - if (hasFilter && m_graphicsLayer->addAnimation(filterVector, IntSize(), anim, keyframes.animationName(), timeOffset)) { + if (hasFilter && m_graphicsLayer->addAnimation(filterVector, IntSize(), anim, keyframes.animationName(), timeOffset)) didAnimateFilter = true; - compositor()->didStartAcceleratedAnimation(CSSPropertyWebkitFilter); - } #endif #if ENABLE(CSS_FILTERS) @@ -1270,7 +1334,7 @@ void RenderLayerBacking::animationFinished(const String& animationName) m_graphicsLayer->removeAnimation(animationName); } -bool RenderLayerBacking::startTransition(double timeOffset, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle) +bool RenderLayerBacking::startTransition(double timeOffset, CSSPropertyID property, const RenderStyle* fromStyle, const RenderStyle* toStyle) { bool didAnimateOpacity = false; bool didAnimateTransform = false; @@ -1278,9 +1342,9 @@ bool RenderLayerBacking::startTransition(double timeOffset, int property, const bool didAnimateFilter = false; #endif - ASSERT(property != cAnimateAll); + ASSERT(property != CSSPropertyInvalid); - if (property == (int)CSSPropertyOpacity) { + if (property == CSSPropertyOpacity) { const Animation* opacityAnim = toStyle->transitionForProperty(CSSPropertyOpacity); if (opacityAnim && !opacityAnim->isEmptyOrZeroDuration()) { KeyframeValueList opacityVector(AnimatedPropertyOpacity); @@ -1295,13 +1359,13 @@ bool RenderLayerBacking::startTransition(double timeOffset, int property, const } } - if (property == (int)CSSPropertyWebkitTransform && m_owningLayer->hasTransform()) { + if (property == CSSPropertyWebkitTransform && m_owningLayer->hasTransform()) { const Animation* transformAnim = toStyle->transitionForProperty(CSSPropertyWebkitTransform); if (transformAnim && !transformAnim->isEmptyOrZeroDuration()) { KeyframeValueList transformVector(AnimatedPropertyWebkitTransform); transformVector.insert(new TransformAnimationValue(0, &fromStyle->transform())); transformVector.insert(new TransformAnimationValue(1, &toStyle->transform())); - if (m_graphicsLayer->addAnimation(transformVector, pixelSnappedIntRect(toRenderBox(renderer())->borderBoxRect()).size(), transformAnim, GraphicsLayer::animationNameForTransition(AnimatedPropertyWebkitTransform), timeOffset)) { + if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->pixelSnappedBorderBoxRect().size(), transformAnim, GraphicsLayer::animationNameForTransition(AnimatedPropertyWebkitTransform), timeOffset)) { // To ensure that the correct transform is visible when the animation ends, also set the final transform. updateLayerTransform(toStyle); didAnimateTransform = true; @@ -1310,7 +1374,7 @@ bool RenderLayerBacking::startTransition(double timeOffset, int property, const } #if ENABLE(CSS_FILTERS) - if (property == (int)CSSPropertyWebkitFilter && m_owningLayer->hasFilter()) { + if (property == CSSPropertyWebkitFilter && m_owningLayer->hasFilter()) { const Animation* filterAnim = toStyle->transitionForProperty(CSSPropertyWebkitFilter); if (filterAnim && !filterAnim->isEmptyOrZeroDuration()) { KeyframeValueList filterVector(AnimatedPropertyWebkitFilter); @@ -1325,17 +1389,6 @@ bool RenderLayerBacking::startTransition(double timeOffset, int property, const } #endif - if (didAnimateOpacity) - compositor()->didStartAcceleratedAnimation(CSSPropertyOpacity); - - if (didAnimateTransform) - compositor()->didStartAcceleratedAnimation(CSSPropertyWebkitTransform); - -#if ENABLE(CSS_FILTERS) - if (didAnimateFilter) - compositor()->didStartAcceleratedAnimation(CSSPropertyWebkitFilter); -#endif - #if ENABLE(CSS_FILTERS) return didAnimateOpacity || didAnimateTransform || didAnimateFilter; #else @@ -1343,14 +1396,14 @@ bool RenderLayerBacking::startTransition(double timeOffset, int property, const #endif } -void RenderLayerBacking::transitionPaused(double timeOffset, int property) +void RenderLayerBacking::transitionPaused(double timeOffset, CSSPropertyID property) { AnimatedPropertyID animatedProperty = cssToGraphicsLayerProperty(property); if (animatedProperty != AnimatedPropertyInvalid) m_graphicsLayer->pauseAnimation(GraphicsLayer::animationNameForTransition(animatedProperty), timeOffset); } -void RenderLayerBacking::transitionFinished(int property) +void RenderLayerBacking::transitionFinished(CSSPropertyID property) { AnimatedPropertyID animatedProperty = cssToGraphicsLayerProperty(property); if (animatedProperty != AnimatedPropertyInvalid) @@ -1387,11 +1440,11 @@ IntRect RenderLayerBacking::compositedBounds() const void RenderLayerBacking::setCompositedBounds(const IntRect& bounds) { m_compositedBounds = bounds; - } -int RenderLayerBacking::graphicsLayerToCSSProperty(AnimatedPropertyID property) + +CSSPropertyID RenderLayerBacking::graphicsLayerToCSSProperty(AnimatedPropertyID property) { - int cssProperty = CSSPropertyInvalid; + CSSPropertyID cssProperty = CSSPropertyInvalid; switch (property) { case AnimatedPropertyWebkitTransform: cssProperty = CSSPropertyWebkitTransform; @@ -1415,7 +1468,7 @@ int RenderLayerBacking::graphicsLayerToCSSProperty(AnimatedPropertyID property) return cssProperty; } -AnimatedPropertyID RenderLayerBacking::cssToGraphicsLayerProperty(int cssProperty) +AnimatedPropertyID RenderLayerBacking::cssToGraphicsLayerProperty(CSSPropertyID cssProperty) { switch (cssProperty) { case CSSPropertyWebkitTransform: @@ -1428,12 +1481,13 @@ AnimatedPropertyID RenderLayerBacking::cssToGraphicsLayerProperty(int cssPropert case CSSPropertyWebkitFilter: return AnimatedPropertyWebkitFilter; #endif - // It's fine if we see other css properties here; they are just not accelerated. + default: + // It's fine if we see other css properties here; they are just not accelerated. + break; } return AnimatedPropertyInvalid; } -#ifndef NDEBUG String RenderLayerBacking::nameForLayer() const { String name = renderer()->renderName(); @@ -1449,7 +1503,6 @@ String RenderLayerBacking::nameForLayer() const return name; } -#endif CompositingLayerType RenderLayerBacking::compositingLayerType() const { @@ -1462,6 +1515,30 @@ CompositingLayerType RenderLayerBacking::compositingLayerType() const return ContainerCompositingLayer; } +double RenderLayerBacking::backingStoreArea() const +{ + double backingArea; + + // m_ancestorClippingLayer and m_clippingLayer are just used for masking, so have no backing. + backingArea = m_graphicsLayer->backingStoreArea(); + if (m_foregroundLayer) + backingArea += m_foregroundLayer->backingStoreArea(); + if (m_maskLayer) + backingArea += m_maskLayer->backingStoreArea(); + + if (m_layerForHorizontalScrollbar) + backingArea += m_layerForHorizontalScrollbar->backingStoreArea(); + + if (m_layerForVerticalScrollbar) + backingArea += m_layerForVerticalScrollbar->backingStoreArea(); + + if (m_layerForScrollCorner) + backingArea += m_layerForScrollCorner->backingStoreArea(); + + return backingArea; +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) + diff --git a/Source/WebCore/rendering/RenderLayerBacking.h b/Source/WebCore/rendering/RenderLayerBacking.h index a75e318b9..a6a03ac77 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.h +++ b/Source/WebCore/rendering/RenderLayerBacking.h @@ -95,19 +95,25 @@ public: // for descendants, but its contents usually render into the window (in which case this returns true). // This returns false for other layers, and when the document layer actually needs to paint into its backing store // for some reason. - bool paintingGoesToWindow() const; + bool paintsIntoWindow() const; + + // Returns true for a composited layer that has no backing store of its own, so + // paints into some ancestor layer. + bool paintsIntoCompositedAncestor() const { return !m_requiresOwnBackingStore; } + + void setRequiresOwnBackingStore(bool flag) { m_requiresOwnBackingStore = flag; } void setContentsNeedDisplay(); // r is in the coordinate space of the layer's render object void setContentsNeedDisplayInRect(const IntRect&); // Notification from the renderer that its content changed. - void contentChanged(RenderLayer::ContentChangeType); + void contentChanged(ContentChangeType); // Interface to start, finish, suspend and resume animations and transitions - bool startTransition(double timeOffset, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle); - void transitionPaused(double timeOffset, int property); - void transitionFinished(int property); + bool startTransition(double, CSSPropertyID, const RenderStyle* fromStyle, const RenderStyle* toStyle); + void transitionPaused(double timeOffset, CSSPropertyID); + void transitionFinished(CSSPropertyID); bool startAnimation(double timeOffset, const Animation* anim, const KeyframeList& keyframes); void animationPaused(double timeOffset, const String& name); @@ -136,6 +142,10 @@ public: virtual bool showDebugBorders(const GraphicsLayer*) const; virtual bool showRepaintCounter(const GraphicsLayer*) const; +#ifndef NDEBUG + virtual void verifyNotPainting(); +#endif + IntRect contentsBox() const; // For informative purposes only. @@ -148,6 +158,11 @@ public: #if ENABLE(CSS_FILTERS) bool canCompositeFilters() const { return m_canCompositeFilters; } #endif + + // Return an estimate of the backing store area (in pixels) allocated by this object's GraphicsLayers. + double backingStoreArea() const; + + String nameForLayer() const; private: void createPrimaryGraphicsLayer(); @@ -186,6 +201,9 @@ private: bool isMainFrameRenderViewLayer() const; + bool paintsBoxDecorations() const; + bool paintsChildren() const; + // Returns true if this compositing layer has no visible content. bool isSimpleContainerCompositingLayer() const; // Returns true if this layer has content that needs to be rendered by painting into the backing store. @@ -204,12 +222,8 @@ private: void paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*, const IntRect& paintDirtyRect, PaintBehavior, GraphicsLayerPaintingPhase, RenderObject* paintingRoot); - static int graphicsLayerToCSSProperty(AnimatedPropertyID); - static AnimatedPropertyID cssToGraphicsLayerProperty(int); - -#ifndef NDEBUG - String nameForLayer() const; -#endif + static CSSPropertyID graphicsLayerToCSSProperty(AnimatedPropertyID); + static AnimatedPropertyID cssToGraphicsLayerProperty(CSSPropertyID); RenderLayer* m_owningLayer; @@ -228,6 +242,7 @@ private: bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work bool m_isMainFrameRenderViewLayer; bool m_usingTiledCacheLayer; + bool m_requiresOwnBackingStore; #if ENABLE(CSS_FILTERS) bool m_canCompositeFilters; #endif diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index dbcbf2158..84ef04bcd 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -53,12 +53,13 @@ #include "ScrollbarTheme.h" #include "ScrollingCoordinator.h" #include "Settings.h" +#include "TiledBacking.h" #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) #include "HTMLMediaElement.h" #endif -#if PROFILE_LAYER_REBUILD +#if !LOG_DISABLED #include <wtf/CurrentTime.h> #endif @@ -128,22 +129,46 @@ private: }; struct CompositingState { - CompositingState(RenderLayer* compAncestor) + CompositingState(RenderLayer* compAncestor, bool testOverlap) : m_compositingAncestor(compAncestor) , m_subtreeIsCompositing(false) + , m_testingOverlap(testOverlap) #ifndef NDEBUG , m_depth(0) #endif { } + CompositingState(const CompositingState& other) + : m_compositingAncestor(other.m_compositingAncestor) + , m_subtreeIsCompositing(other.m_subtreeIsCompositing) + , m_testingOverlap(other.m_testingOverlap) +#ifndef NDEBUG + , m_depth(other.m_depth + 1) +#endif + { + } + RenderLayer* m_compositingAncestor; bool m_subtreeIsCompositing; + bool m_testingOverlap; #ifndef NDEBUG int m_depth; #endif }; + +static inline bool compositingLogEnabled() +{ +#if !LOG_DISABLED + return LogCompositing.state == WTFLogChannelOn; +#else + return false; +#endif +} + +#define PIXELS_PER_MEGAPIXEL 1000000.0 + RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) : m_renderView(renderView) , m_updateCompositingLayersTimer(this, &RenderLayerCompositor::updateCompositingLayersTimerFired) @@ -152,17 +177,21 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) , m_compositedLayerCount(0) , m_showDebugBorders(false) , m_showRepaintCounter(false) + , m_acceleratedDrawingEnabled(false) , m_compositingConsultsOverlap(true) - , m_compositingDependsOnGeometry(false) - , m_compositingNeedsUpdate(false) + , m_reevaluateCompositingAfterLayout(false) , m_compositing(false) , m_compositingLayersNeedRebuild(false) , m_flushingLayers(false) , m_forceCompositingMode(false) , m_rootLayerAttachment(RootLayerUnattached) -#if PROFILE_LAYER_REBUILD +#if !LOG_DISABLED , m_rootLayerUpdateCount(0) -#endif // PROFILE_LAYER_REBUILD + , m_obligateCompositedLayerCount(0) + , m_secondaryCompositedLayerCount(0) + , m_obligatoryBackingAreaMegaPixels(0) + , m_secondaryBackingAreaMegaPixels(0) +#endif { } @@ -190,6 +219,7 @@ void RenderLayerCompositor::cacheAcceleratedCompositingFlags() bool showDebugBorders = false; bool showRepaintCounter = false; bool forceCompositingMode = false; + bool acceleratedDrawingEnabled = false; if (Settings* settings = m_renderView->document()->settings()) { hasAcceleratedCompositing = settings->acceleratedCompositingEnabled(); @@ -212,8 +242,9 @@ void RenderLayerCompositor::cacheAcceleratedCompositingFlags() if (forceCompositingMode && m_renderView->document()->ownerElement()) forceCompositingMode = settings->acceleratedCompositingForScrollableFramesEnabled() && requiresCompositingForScrollableFrame(); - } + acceleratedDrawingEnabled = settings->acceleratedDrawingEnabled(); + } if (hasAcceleratedCompositing != m_hasAcceleratedCompositing || showDebugBorders != m_showDebugBorders || showRepaintCounter != m_showRepaintCounter || forceCompositingMode != m_forceCompositingMode) setCompositingLayersNeedRebuild(); @@ -222,6 +253,7 @@ void RenderLayerCompositor::cacheAcceleratedCompositingFlags() m_showDebugBorders = showDebugBorders; m_showRepaintCounter = showRepaintCounter; m_forceCompositingMode = forceCompositingMode; + m_acceleratedDrawingEnabled = acceleratedDrawingEnabled; } bool RenderLayerCompositor::canRender3DTransforms() const @@ -296,7 +328,7 @@ void RenderLayerCompositor::scheduleCompositingLayerUpdate() void RenderLayerCompositor::updateCompositingLayersTimerFired(Timer<RenderLayerCompositor>*) { - updateCompositingLayers(); + updateCompositingLayers(CompositingUpdateAfterLayout); } bool RenderLayerCompositor::hasAnyAdditionalCompositedLayers(const RenderLayer* rootLayer) const @@ -315,14 +347,15 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update if (m_forceCompositingMode && !m_compositing) enableCompositingMode(true); - if (!m_compositingDependsOnGeometry && !m_compositing && !m_compositingNeedsUpdate) + if (!m_reevaluateCompositingAfterLayout && !m_compositing) return; - bool checkForHierarchyUpdate = m_compositingDependsOnGeometry; + bool checkForHierarchyUpdate = m_reevaluateCompositingAfterLayout; bool needGeometryUpdate = false; switch (updateType) { - case CompositingUpdateAfterLayoutOrStyleChange: + case CompositingUpdateAfterStyleChange: + case CompositingUpdateAfterLayout: case CompositingUpdateOnHitTest: checkForHierarchyUpdate = true; break; @@ -338,22 +371,28 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update return; bool needHierarchyUpdate = m_compositingLayersNeedRebuild; + bool isFullUpdate = !updateRoot; if (!updateRoot || m_compositingConsultsOverlap) { // Only clear the flag if we're updating the entire hierarchy. m_compositingLayersNeedRebuild = false; updateRoot = rootRenderLayer(); } -#if PROFILE_LAYER_REBUILD - ++m_rootLayerUpdateCount; - - double startTime = WTF::currentTime(); -#endif + if (isFullUpdate && updateType == CompositingUpdateAfterLayout) + m_reevaluateCompositingAfterLayout = false; + +#if !LOG_DISABLED + double startTime = 0; + if (compositingLogEnabled()) { + ++m_rootLayerUpdateCount; + startTime = currentTime(); + } +#endif if (checkForHierarchyUpdate) { // Go through the layers in presentation order, so that we can compute which RenderLayers need compositing layers. // FIXME: we could maybe do this and the hierarchy udpate in one pass, but the parenting logic would be more complex. - CompositingState compState(updateRoot); + CompositingState compState(updateRoot, m_compositingConsultsOverlap); bool layersChanged = false; if (m_compositingConsultsOverlap) { OverlapMap overlapTestRequestMap; @@ -364,13 +403,27 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update needHierarchyUpdate |= layersChanged; } +#if !LOG_DISABLED + if (compositingLogEnabled() && isFullUpdate && (needHierarchyUpdate || needGeometryUpdate)) { + m_obligateCompositedLayerCount = 0; + m_secondaryCompositedLayerCount = 0; + m_obligatoryBackingAreaMegaPixels = 0; + m_secondaryBackingAreaMegaPixels = 0; + + Frame* frame = m_renderView->frameView()->frame(); + bool isMainFrame = !m_renderView->document()->ownerElement(); + LOG(Compositing, "\nUpdate %d of %s. Overlap testing is %s\n", m_rootLayerUpdateCount, isMainFrame ? "main frame" : frame->tree()->uniqueName().string().utf8().data(), + m_compositingConsultsOverlap ? "on" : "off"); + } +#endif + if (needHierarchyUpdate) { // Update the hierarchy of the compositing layers. Vector<GraphicsLayer*> childList; - rebuildCompositingLayerTree(updateRoot, childList); + rebuildCompositingLayerTree(updateRoot, childList, 0); // Host the document layer in the RenderView's root layer. - if (updateRoot == rootRenderLayer()) { + if (isFullUpdate) { // Even when childList is empty, don't drop out of compositing mode if there are // composited layers that we didn't hit in our traversal (e.g. because of visibility:hidden). if (childList.isEmpty() && !hasAnyAdditionalCompositedLayers(updateRoot)) @@ -381,22 +434,45 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update } else if (needGeometryUpdate) { // We just need to do a geometry update. This is only used for position:fixed scrolling; // most of the time, geometry is updated via RenderLayer::styleChanged(). - updateLayerTreeGeometry(updateRoot); + updateLayerTreeGeometry(updateRoot, 0); } -#if PROFILE_LAYER_REBUILD - double endTime = WTF::currentTime(); - if (updateRoot == rootRenderLayer()) - fprintf(stderr, "Update %d: computeCompositingRequirements for the world took %fms\n", - m_rootLayerUpdateCount, 1000.0 * (endTime - startTime)); +#if !LOG_DISABLED + if (compositingLogEnabled() && isFullUpdate && (needHierarchyUpdate || needGeometryUpdate)) { + double endTime = currentTime(); + LOG(Compositing, "Total layers primary secondary obligatory backing (MP) secondary backing(MP) total backing (MP) update time (ms)\n"); + + LOG(Compositing, "%8d %11d %9d %20.2f %22.2f %22.2f %18.2f\n", + m_obligateCompositedLayerCount + m_secondaryCompositedLayerCount, m_obligateCompositedLayerCount, + m_secondaryCompositedLayerCount, m_obligatoryBackingAreaMegaPixels, m_secondaryBackingAreaMegaPixels, m_obligatoryBackingAreaMegaPixels + m_secondaryBackingAreaMegaPixels, 1000.0 * (endTime - startTime)); + } #endif ASSERT(updateRoot || !m_compositingLayersNeedRebuild); if (!hasAcceleratedCompositing()) enableCompositingMode(false); +} + +#if !LOG_DISABLED +void RenderLayerCompositor::logLayerInfo(const RenderLayer* layer, int depth) +{ + if (!compositingLogEnabled()) + return; + + RenderLayerBacking* backing = layer->backing(); + if (requiresCompositingLayer(layer) || layer->isRootLayer()) { + ++m_obligateCompositedLayerCount; + m_obligatoryBackingAreaMegaPixels += backing->backingStoreArea() / PIXELS_PER_MEGAPIXEL; + } else { + ++m_secondaryCompositedLayerCount; + m_secondaryBackingAreaMegaPixels += backing->backingStoreArea() / PIXELS_PER_MEGAPIXEL; + } - m_compositingNeedsUpdate = false; + LOG(Compositing, "%*p %dx%d %.3fMP (%s) %s\n", 12 + depth * 2, layer, backing->compositedBounds().width(), backing->compositedBounds().height(), + backing->backingStoreArea() / PIXELS_PER_MEGAPIXEL, + reasonForCompositing(layer), layer->backing()->nameForLayer().utf8().data()); } +#endif bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeRepaint shouldRepaint) { @@ -405,12 +481,7 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR if (needsToBeComposited(layer)) { enableCompositingMode(); - // Non-identity 3D transforms turn off the testing of overlap. - if (hasNonIdentity3DTransform(layer->renderer())) - setCompositingConsultsOverlap(false); - if (!layer->backing()) { - // If we need to repaint, do so before making backing if (shouldRepaint == CompositingChangeRepaintNow) repaintOnCompositingChange(layer); @@ -420,18 +491,9 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR // The RenderLayer's needs to update repaint rects here, because the target // repaintContainer may have changed after becoming a composited layer. // https://bugs.webkit.org/show_bug.cgi?id=80641 - layer->computeRepaintRects(); + if (layer->parent()) + layer->computeRepaintRects(); -#if PLATFORM(MAC) && USE(CA) - Settings* settings = m_renderView->document()->settings(); - if (settings && settings->acceleratedDrawingEnabled()) - layer->backing()->graphicsLayer()->setAcceleratesDrawing(true); - else if (layer->renderer()->isCanvas()) { - HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(layer->renderer()->node()); - if (canvas->shouldAccelerate(canvas->size())) - layer->backing()->graphicsLayer()->setAcceleratesDrawing(true); - } -#endif layerChanged = true; } } else { @@ -514,83 +576,7 @@ IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* laye { if (!canBeComposited(layer)) return IntRect(); - - LayoutRect boundingBoxRect = layer->localBoundingBox(); - if (layer->renderer()->isRoot()) { - // If the root layer becomes composited (e.g. because some descendant with negative z-index is composited), - // then it has to be big enough to cover the viewport in order to display the background. This is akin - // to the code in RenderBox::paintRootBoxFillLayers(). - if (m_renderView->frameView()) { - LayoutUnit rw = m_renderView->frameView()->contentsWidth(); - LayoutUnit rh = m_renderView->frameView()->contentsHeight(); - - boundingBoxRect.setWidth(max(boundingBoxRect.width(), rw - boundingBoxRect.x())); - boundingBoxRect.setHeight(max(boundingBoxRect.height(), rh - boundingBoxRect.y())); - } - } - - LayoutRect unionBounds = boundingBoxRect; - - if (layer->renderer()->hasOverflowClip() || layer->renderer()->hasMask()) { - LayoutPoint ancestorRelOffset; - layer->convertToLayerCoords(ancestorLayer, ancestorRelOffset); - boundingBoxRect.moveBy(ancestorRelOffset); - return pixelSnappedIntRect(boundingBoxRect); - } - - if (RenderLayer* reflection = layer->reflectionLayer()) { - if (!reflection->isComposited()) { - LayoutRect childUnionBounds = calculateCompositedBounds(reflection, layer); - unionBounds.unite(childUnionBounds); - } - } - - ASSERT(layer->isStackingContext() || (!layer->m_posZOrderList || layer->m_posZOrderList->size() == 0)); - - if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { - size_t listSize = negZOrderList->size(); - for (size_t i = 0; i < listSize; ++i) { - RenderLayer* curLayer = negZOrderList->at(i); - if (!curLayer->isComposited()) { - LayoutRect childUnionBounds = calculateCompositedBounds(curLayer, layer); - unionBounds.unite(childUnionBounds); - } - } - } - - if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { - size_t listSize = posZOrderList->size(); - for (size_t i = 0; i < listSize; ++i) { - RenderLayer* curLayer = posZOrderList->at(i); - if (!curLayer->isComposited()) { - LayoutRect childUnionBounds = calculateCompositedBounds(curLayer, layer); - unionBounds.unite(childUnionBounds); - } - } - } - - if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { - size_t listSize = normalFlowList->size(); - for (size_t i = 0; i < listSize; ++i) { - RenderLayer* curLayer = normalFlowList->at(i); - if (!curLayer->isComposited()) { - LayoutRect curAbsBounds = calculateCompositedBounds(curLayer, layer); - unionBounds.unite(curAbsBounds); - } - } - } - - if (layer->paintsWithTransform(PaintBehaviorNormal)) { - TransformationMatrix* affineTrans = layer->transform(); - boundingBoxRect = affineTrans->mapRect(boundingBoxRect); - unionBounds = affineTrans->mapRect(unionBounds); - } - - LayoutPoint ancestorRelOffset; - layer->convertToLayerCoords(ancestorLayer, ancestorRelOffset); - unionBounds.moveBy(ancestorRelOffset); - - return pixelSnappedIntRect(unionBounds); + return pixelSnappedIntRect(RenderLayer::calculateLayerBounds(layer, ancestorLayer)); } void RenderLayerCompositor::layerWasAdded(RenderLayer* /*parent*/, RenderLayer* /*child*/) @@ -605,7 +591,7 @@ void RenderLayerCompositor::layerWillBeRemoved(RenderLayer* parent, RenderLayer* setCompositingParent(child, 0); - RenderLayer* compLayer = parent->enclosingCompositingLayer(); + RenderLayer* compLayer = parent->enclosingCompositingLayerForRepaint(); if (compLayer) { ASSERT(compLayer->backing()); LayoutRect compBounds = child->backing()->compositedBounds(); @@ -643,12 +629,12 @@ void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer* if (!boundsComputed) { layerBounds = layer->renderer()->localToAbsoluteQuad(FloatRect(layer->localBoundingBox())).enclosingBoundingBox(); + // Empty rects never intersect, but we need them to for the purposes of overlap testing. + if (layerBounds.isEmpty()) + layerBounds.setSize(IntSize(1, 1)); boundsComputed = true; } - if (layerBounds.isEmpty()) - return; - IntRect clipRect = pixelSnappedIntRect(layer->backgroundClipRect(rootRenderLayer(), 0, true).rect()); // FIXME: Incorrect for CSS regions. clipRect.scale(pageScaleFactor()); clipRect.intersect(layerBounds); @@ -664,6 +650,10 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren bool haveComputedBounds = false; addToOverlapMap(overlapMap, layer, bounds, haveComputedBounds); +#if !ASSERT_DISABLED + LayerListMutationDetector mutationChecker(layer); +#endif + if (layer->isStackingContext()) { if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { size_t listSize = negZOrderList->size(); @@ -674,7 +664,6 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren } } - ASSERT(!layer->m_normalFlowListDirty); if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) { @@ -703,12 +692,11 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren // must be compositing so that its contents render over that child. // This implies that its positive z-index children must also be compositing. // -void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, OverlapMap* overlapMap, struct CompositingState& compositingState, bool& layersChanged) +void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, OverlapMap* overlapMap, CompositingState& compositingState, bool& layersChanged) { layer->updateLayerPosition(); - layer->updateZOrderLists(); - layer->updateNormalFlowList(); - + layer->updateLayerListsIfNeeded(); + // Clear the flag layer->setHasCompositingDescendant(false); @@ -716,10 +704,12 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O bool haveComputedBounds = false; IntRect absBounds; - if (overlapMap && !overlapMap->isEmpty()) { + if (overlapMap && !overlapMap->isEmpty() && compositingState.m_testingOverlap) { // If we're testing for overlap, we only need to composite if we overlap something that is already composited. absBounds = layer->renderer()->localToAbsoluteQuad(FloatRect(layer->localBoundingBox())).enclosingBoundingBox(); // Empty rects never intersect, but we need them to for the purposes of overlap testing. + if (absBounds.isEmpty()) + absBounds.setSize(IntSize(1, 1)); haveComputedBounds = true; mustOverlapCompositedLayers = overlapMap->overlapsLayers(absBounds); } @@ -729,10 +719,8 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O // The children of this layer don't need to composite, unless there is // a compositing layer among them, so start by inheriting the compositing // ancestor with m_subtreeIsCompositing set to false. - CompositingState childState(compositingState.m_compositingAncestor); -#ifndef NDEBUG - childState.m_depth = compositingState.m_depth + 1; -#endif + CompositingState childState(compositingState); + childState.m_subtreeIsCompositing = false; bool willBeComposited = needsToBeComposited(layer); if (willBeComposited) { @@ -743,6 +731,11 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O if (overlapMap) overlapMap->pushCompositingContainer(); + + if (hasNonAffineTransform(layer->renderer()) || isRunningAcceleratedTransformAnimation(layer->renderer())) { + // If we have a 3D transform, or are animating transform, then turn overlap testing off. + childState.m_testingOverlap = false; + } } #if ENABLE(VIDEO) @@ -753,8 +746,11 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O childState.m_subtreeIsCompositing = true; #endif +#if !ASSERT_DISABLED + LayerListMutationDetector mutationChecker(layer); +#endif + if (layer->isStackingContext()) { - ASSERT(!layer->m_zOrderListsDirty); if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { size_t listSize = negZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { @@ -775,7 +771,6 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O } } - ASSERT(!layer->m_normalFlowListDirty); if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) { @@ -822,25 +817,36 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O } ASSERT(willBeComposited == needsToBeComposited(layer)); - if (layer->reflectionLayer()) + if (layer->reflectionLayer()) { + // FIXME: Shouldn't we call computeCompositingRequirements to handle a reflection overlapping with another renderer? layer->reflectionLayer()->setMustOverlapCompositedLayers(willBeComposited); + } // Subsequent layers in the parent stacking context also need to composite. if (childState.m_subtreeIsCompositing) compositingState.m_subtreeIsCompositing = true; + // We have to keep overlap testing disabled for later layers. + if (!childState.m_testingOverlap) + compositingState.m_testingOverlap = false; + // Set the flag to say that this SC has compositing children. layer->setHasCompositingDescendant(childState.m_subtreeIsCompositing); // setHasCompositingDescendant() may have changed the answer to needsToBeComposited() when clipping, // so test that again. - if (!willBeComposited && canBeComposited(layer) && clipsCompositingDescendants(layer)) { - childState.m_compositingAncestor = layer; - if (overlapMap) { - overlapMap->pushCompositingContainer(); - addToOverlapMapRecursive(*overlapMap, layer); - } - willBeComposited = true; + if (canBeComposited(layer) && clipsCompositingDescendants(layer)) { + if (!willBeComposited) { + childState.m_compositingAncestor = layer; + if (overlapMap) { + overlapMap->pushCompositingContainer(); + addToOverlapMapRecursive(*overlapMap, layer); + } + willBeComposited = true; + } + + // We're done processing an element that clips. The container can keep testing overlap. + compositingState.m_testingOverlap = true; } if (overlapMap && childState.m_compositingAncestor == layer && !layer->isRootLayer()) @@ -905,7 +911,7 @@ bool RenderLayerCompositor::canAccelerateVideoRendering(RenderVideo* o) const } #endif -void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vector<GraphicsLayer*>& childLayersOfEnclosingLayer) +void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vector<GraphicsLayer*>& childLayersOfEnclosingLayer, int depth) { // Make the layer compositing if necessary, and set up clipping and content layers. // Note that we can only do work here that is independent of whether the descendant layers @@ -927,6 +933,12 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect if (!layer->parent()) updateRootLayerPosition(); + +#if !LOG_DISABLED + logLayerInfo(layer, depth); +#else + UNUSED_PARAM(depth); +#endif } // If this layer has backing, then we are collecting its children, otherwise appending @@ -934,14 +946,16 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect Vector<GraphicsLayer*> layerChildren; Vector<GraphicsLayer*>& childList = layerBacking ? layerChildren : childLayersOfEnclosingLayer; - if (layer->isStackingContext()) { - ASSERT(!layer->m_zOrderListsDirty); +#if !ASSERT_DISABLED + LayerListMutationDetector mutationChecker(layer); +#endif + if (layer->isStackingContext()) { if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { size_t listSize = negZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = negZOrderList->at(i); - rebuildCompositingLayerTree(curLayer, childList); + rebuildCompositingLayerTree(curLayer, childList, depth + 1); } } @@ -950,12 +964,11 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect childList.append(layerBacking->foregroundLayer()); } - ASSERT(!layer->m_normalFlowListDirty); if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = normalFlowList->at(i); - rebuildCompositingLayerTree(curLayer, childList); + rebuildCompositingLayerTree(curLayer, childList, depth + 1); } } @@ -964,7 +977,7 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect size_t listSize = posZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = posZOrderList->at(i); - rebuildCompositingLayerTree(curLayer, childList); + rebuildCompositingLayerTree(curLayer, childList, depth + 1); } } } @@ -1027,8 +1040,8 @@ void RenderLayerCompositor::frameViewDidScroll() FrameView* frameView = m_renderView->frameView(); IntPoint scrollPosition = frameView->scrollPosition(); - if (RenderLayerBacking* backing = rootRenderLayer()->backing()) - backing->graphicsLayer()->visibleRectChanged(frameView->visibleContentRect(false /* exclude scrollbars */)); + if (TiledBacking* tiledBacking = frameView->tiledBacking()) + tiledBacking->visibleRectChanged(frameView->visibleContentRect(false /* exclude scrollbars */)); if (!m_scrollLayer) return; @@ -1045,7 +1058,7 @@ void RenderLayerCompositor::frameViewDidScroll() String RenderLayerCompositor::layerTreeAsText(bool showDebugInfo) { - updateCompositingLayers(); + updateCompositingLayers(CompositingUpdateAfterLayout); if (!m_rootContentLayer) return String(); @@ -1089,7 +1102,7 @@ bool RenderLayerCompositor::parentFrameContentLayers(RenderPart* renderer) } // This just updates layer geometry without changing the hierarchy. -void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer) +void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer, int depth) { if (RenderLayerBacking* layerBacking = layer->backing()) { // The compositing state of all our children has been updated already, so now @@ -1106,30 +1119,37 @@ void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer) if (!layer->parent()) updateRootLayerPosition(); + +#if !LOG_DISABLED + logLayerInfo(layer, depth); +#else + UNUSED_PARAM(depth); +#endif } - if (layer->isStackingContext()) { - ASSERT(!layer->m_zOrderListsDirty); +#if !ASSERT_DISABLED + LayerListMutationDetector mutationChecker(layer); +#endif + if (layer->isStackingContext()) { if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { size_t listSize = negZOrderList->size(); for (size_t i = 0; i < listSize; ++i) - updateLayerTreeGeometry(negZOrderList->at(i)); + updateLayerTreeGeometry(negZOrderList->at(i), depth + 1); } } - ASSERT(!layer->m_normalFlowListDirty); if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) - updateLayerTreeGeometry(normalFlowList->at(i)); + updateLayerTreeGeometry(normalFlowList->at(i), depth + 1); } if (layer->isStackingContext()) { if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { size_t listSize = posZOrderList->size(); for (size_t i = 0; i < listSize; ++i) - updateLayerTreeGeometry(posZOrderList->at(i)); + updateLayerTreeGeometry(posZOrderList->at(i), depth + 1); } } } @@ -1157,6 +1177,10 @@ void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* com if (!layer->hasCompositingDescendant()) return; + +#if !ASSERT_DISABLED + LayerListMutationDetector mutationChecker(layer); +#endif if (layer->isStackingContext()) { if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { @@ -1190,9 +1214,13 @@ void RenderLayerCompositor::repaintCompositedLayersAbsoluteRect(const IntRect& a void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const IntRect& rect) { // FIXME: This method does not work correctly with transforms. - if (layer->isComposited()) + if (layer->isComposited() && !layer->backing()->paintsIntoCompositedAncestor()) layer->setBackingNeedsRepaintInRect(rect); +#if !ASSERT_DISABLED + LayerListMutationDetector mutationChecker(layer); +#endif + if (layer->hasCompositingDescendant()) { if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { size_t listSize = negZOrderList->size(); @@ -1301,15 +1329,6 @@ void RenderLayerCompositor::updateRootLayerPosition() #endif } -void RenderLayerCompositor::didStartAcceleratedAnimation(CSSPropertyID property) -{ - // If an accelerated animation or transition runs, we have to turn off overlap checking because - // we don't do layout for every frame, but we have to ensure that the layering is - // correct between the animating object and other objects on the page. - if (property == CSSPropertyWebkitTransform) - setCompositingConsultsOverlap(false); -} - bool RenderLayerCompositor::has3DContent() const { return layerHas3DContent(rootRenderLayer()); @@ -1381,22 +1400,106 @@ bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) c } // The root layer always has a compositing layer, but it may not have backing. return requiresCompositingForTransform(renderer) - || requiresCompositingForVideo(renderer) - || requiresCompositingForCanvas(renderer) - || requiresCompositingForPlugin(renderer) - || requiresCompositingForFrame(renderer) - || (canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden) - || clipsCompositingDescendants(layer) - || requiresCompositingForAnimation(renderer) - || requiresCompositingForFilters(renderer) - || requiresCompositingForPosition(renderer, layer); + || requiresCompositingForVideo(renderer) + || requiresCompositingForCanvas(renderer) + || requiresCompositingForPlugin(renderer) + || requiresCompositingForFrame(renderer) + || (canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden) + || clipsCompositingDescendants(layer) + || requiresCompositingForAnimation(renderer) + || requiresCompositingForFilters(renderer) + || requiresCompositingForPosition(renderer, layer); } bool RenderLayerCompositor::canBeComposited(const RenderLayer* layer) const { - return m_hasAcceleratedCompositing && layer->isSelfPaintingLayer(); + // FIXME: We disable accelerated compositing for elements in a RenderFlowThread as it doesn't work properly. + // See http://webkit.org/b/84900 to re-enable it. + return m_hasAcceleratedCompositing && layer->isSelfPaintingLayer() && !layer->renderer()->inRenderFlowThread(); } +bool RenderLayerCompositor::requiresOwnBackingStore(const RenderLayer* layer, const RenderLayer* compositingAncestorLayer) const +{ + RenderObject* renderer = layer->renderer(); + if (compositingAncestorLayer + && !(compositingAncestorLayer->backing()->graphicsLayer()->drawsContent() + || compositingAncestorLayer->backing()->paintsIntoWindow() + || compositingAncestorLayer->backing()->paintsIntoCompositedAncestor())) + return true; + + return layer->isRootLayer() + || layer->transform() // note: excludes perspective and transformStyle3D. + || requiresCompositingForVideo(renderer) + || requiresCompositingForCanvas(renderer) + || requiresCompositingForPlugin(renderer) + || requiresCompositingForFrame(renderer) + || (canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden) + || requiresCompositingForAnimation(renderer) + || requiresCompositingForFilters(renderer) + || requiresCompositingForPosition(renderer, layer) + || renderer->isTransparent() + || renderer->hasMask() + || renderer->hasReflection() + || renderer->hasFilter() + || layer->mustOverlapCompositedLayers(); +} + +#if !LOG_DISABLED +const char* RenderLayerCompositor::reasonForCompositing(const RenderLayer* layer) +{ + RenderObject* renderer = layer->renderer(); + if (layer->isReflection()) { + renderer = renderer->parent(); + layer = toRenderBoxModelObject(renderer)->layer(); + } + + if (renderer->hasTransform() && renderer->style()->hasPerspective()) + return "perspective"; + + if (renderer->hasTransform() && (renderer->style()->transformStyle3D() == TransformStyle3DPreserve3D)) + return "preserve-3d"; + + if (renderer->hasTransform()) + return "transform"; + + if (requiresCompositingForVideo(renderer)) + return "video"; + + if (requiresCompositingForCanvas(renderer)) + return "canvas"; + + if (requiresCompositingForPlugin(renderer)) + return "plugin"; + + if (requiresCompositingForFrame(renderer)) + return "iframe"; + + if ((canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden)) + return "backface-visibility: hidden"; + + if (clipsCompositingDescendants(layer)) + return "clips compositing descendants"; + + if (requiresCompositingForAnimation(renderer)) + return "animation"; + + if (requiresCompositingForFilters(renderer)) + return "filters"; + + if (requiresCompositingForPosition(renderer, layer)) + return "position: fixed"; + + // This includes layers made composited by requiresCompositingWhenDescendantsAreCompositing(). + if (layer->mustOverlapCompositedLayers()) + return "overlap/stacking"; + + if (inCompositingMode() && layer->isRootLayer()) + return "root"; + + return ""; +} +#endif + // Return true if the given layer has some ancestor in the RenderLayer hierarchy that clips, // up to the enclosing compositing ancestor. This is required because compositing layers are parented // according to the z-order hierarchy, yet clipping goes down the renderer hierarchy. @@ -1510,7 +1613,7 @@ bool RenderLayerCompositor::requiresCompositingForPlugin(RenderObject* renderer) if (!composite) return false; - m_compositingDependsOnGeometry = true; + m_reevaluateCompositingAfterLayout = true; RenderWidget* pluginRenderer = toRenderWidget(renderer); // If we can't reliably know the size of the plugin yet, don't change compositing state. @@ -1532,7 +1635,7 @@ bool RenderLayerCompositor::requiresCompositingForFrame(RenderObject* renderer) if (!frameRenderer->requiresAcceleratedCompositing()) return false; - m_compositingDependsOnGeometry = true; + m_reevaluateCompositingAfterLayout = true; RenderLayerCompositor* innerCompositor = frameContentsCompositor(frameRenderer); if (!innerCompositor || !innerCompositor->shouldPropagateCompositingToEnclosingFrame()) @@ -1598,7 +1701,7 @@ bool RenderLayerCompositor::requiresCompositingForPosition(RenderObject* rendere RenderObject* container = renderer->container(); // If the renderer is not hooked up yet then we have to wait until it is. if (!container) { - m_compositingNeedsUpdate = true; + m_reevaluateCompositingAfterLayout = true; return false; } @@ -1609,26 +1712,34 @@ bool RenderLayerCompositor::requiresCompositingForPosition(RenderObject* rendere // Fixed position elements that are invisible in the current view don't get their own layer. FrameView* frameView = m_renderView->frameView(); - if (frameView && !layer->absoluteBoundingBox().intersects(LayoutRect(frameView->scrollXForFixedPosition(), frameView->scrollYForFixedPosition(), frameView->layoutWidth(), frameView->layoutHeight()))) + if (frameView && !layer->absoluteBoundingBox().intersects(IntRect(frameView->scrollXForFixedPosition(), frameView->scrollYForFixedPosition(), frameView->layoutWidth(), frameView->layoutHeight()))) return false; return true; } -bool RenderLayerCompositor::hasNonIdentity3DTransform(RenderObject* renderer) const +bool RenderLayerCompositor::hasNonAffineTransform(RenderObject* renderer) const { if (!renderer->hasTransform()) return false; - if (renderer->style()->hasPerspective()) - return true; - if (TransformationMatrix* transform = toRenderBoxModelObject(renderer)->layer()->transform()) return !transform->isAffine(); return false; } +bool RenderLayerCompositor::isRunningAcceleratedTransformAnimation(RenderObject* renderer) const +{ + if (!(m_compositingTriggers & ChromeClient::AnimationTrigger)) + return false; + + if (AnimationController* animController = renderer->animation()) + return animController->isRunningAnimationOnRenderer(renderer, CSSPropertyWebkitTransform); + + return false; +} + // If an element has negative z-index children, those children render in front of the // layer background, so we need an extra 'contents' layer for the foreground of the layer // object. @@ -2098,7 +2209,7 @@ void RenderLayerCompositor::updateRootLayerAttachment() void RenderLayerCompositor::rootLayerAttachmentChanged() { - // The attachment can affect whether the RenderView layer's paintingGoesToWindow() behavior, + // The attachment can affect whether the RenderView layer's paintsIntoWindow() behavior, // so call updateGraphicsLayerGeometry() to udpate that. RenderLayer* layer = m_renderView->layer(); if (RenderLayerBacking* backing = layer ? layer->backing() : 0) @@ -2135,6 +2246,12 @@ bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const style->transform().has3DOperation())) return true; + const_cast<RenderLayer*>(layer)->updateLayerListsIfNeeded(); + +#if !ASSERT_DISABLED + LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(layer)); +#endif + if (layer->isStackingContext()) { if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { size_t listSize = negZOrderList->size(); diff --git a/Source/WebCore/rendering/RenderLayerCompositor.h b/Source/WebCore/rendering/RenderLayerCompositor.h index 98a2a9f95..e294b5866 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.h +++ b/Source/WebCore/rendering/RenderLayerCompositor.h @@ -32,8 +32,6 @@ namespace WebCore { -#define PROFILE_LAYER_REBUILD 0 - class GraphicsLayer; class RenderEmbeddedObject; class RenderPart; @@ -43,7 +41,8 @@ class RenderVideo; #endif enum CompositingUpdateType { - CompositingUpdateAfterLayoutOrStyleChange, + CompositingUpdateAfterStyleChange, + CompositingUpdateAfterLayout, CompositingUpdateOnHitTest, CompositingUpdateOnScroll }; @@ -66,7 +65,9 @@ public: // This will make a compositing layer at the root automatically, and hook up to // the native view/window system. void enableCompositingMode(bool enable = true); - + + bool inForcedCompositingMode() const { return m_forceCompositingMode; } + // Returns true if the accelerated compositing is enabled bool hasAcceleratedCompositing() const { return m_hasAcceleratedCompositing; } @@ -98,7 +99,7 @@ public: void didFlushChangesForLayer(RenderLayer*); // Rebuild the tree of compositing layers - void updateCompositingLayers(CompositingUpdateType = CompositingUpdateAfterLayoutOrStyleChange, RenderLayer* updateRoot = 0); + void updateCompositingLayers(CompositingUpdateType, RenderLayer* updateRoot = 0); // This is only used when state changes and we do not exepect a style update or layout to happen soon (e.g. when // we discover that an iframe is overlapped during painting). void scheduleCompositingLayerUpdate(); @@ -134,6 +135,9 @@ public: // Repaint parts of all composited layers that intersect the given absolute rectangle. void repaintCompositedLayersAbsoluteRect(const IntRect&); + // Returns true if the given layer needs it own backing store. + bool requiresOwnBackingStore(const RenderLayer*, const RenderLayer* compositingAncestorLayer) const; + RenderLayer* rootRenderLayer() const; GraphicsLayer* rootGraphicsLayer() const; GraphicsLayer* scrollLayer() const; @@ -160,8 +164,6 @@ public: --m_compositedLayerCount; } - void didStartAcceleratedAnimation(CSSPropertyID); - #if ENABLE(VIDEO) // Use by RenderVideo to ask if it should try to use accelerated compositing. bool canAccelerateVideoRendering(RenderVideo*) const; @@ -197,6 +199,7 @@ public: virtual void didCommitChangesForLayer(const GraphicsLayer*) const; bool keepLayersPixelAligned() const; + bool acceleratedDrawingEnabled() const { return m_acceleratedDrawingEnabled; } void deviceOrPageScaleFactorChanged(); @@ -244,18 +247,19 @@ private: void computeCompositingRequirements(RenderLayer*, OverlapMap*, struct CompositingState&, bool& layersChanged); // Recurses down the tree, parenting descendant compositing layers and collecting an array of child layers for the current compositing layer. - void rebuildCompositingLayerTree(RenderLayer*, Vector<GraphicsLayer*>& childGraphicsLayersOfEnclosingLayer); + void rebuildCompositingLayerTree(RenderLayer*, Vector<GraphicsLayer*>& childGraphicsLayersOfEnclosingLayer, int depth); // Recurses down the tree, updating layer geometry only. - void updateLayerTreeGeometry(RenderLayer*); + void updateLayerTreeGeometry(RenderLayer*, int depth); // Hook compositing layers together void setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer); void removeCompositedChildren(RenderLayer*); bool layerHas3DContent(const RenderLayer*) const; - bool hasNonIdentity3DTransform(RenderObject*) const; - + bool hasNonAffineTransform(RenderObject*) const; + bool isRunningAcceleratedTransformAnimation(RenderObject*) const; + bool hasAnyAdditionalCompositedLayers(const RenderLayer* rootLayer) const; void ensureRootLayer(); @@ -295,6 +299,11 @@ private: bool requiresContentShadowLayer() const; #endif +#if !LOG_DISABLED + const char* reasonForCompositing(const RenderLayer*); + void logLayerInfo(const RenderLayer*, int depth); +#endif + private: RenderView* m_renderView; OwnPtr<GraphicsLayer> m_rootContentLayer; @@ -306,14 +315,12 @@ private: int m_compositedLayerCount; bool m_showDebugBorders; bool m_showRepaintCounter; + bool m_acceleratedDrawingEnabled; bool m_compositingConsultsOverlap; // When true, we have to wait until layout has happened before we can decide whether to enter compositing mode, // because only then do we know the final size of plugins and iframes. - // FIXME: once set, this is never cleared. - mutable bool m_compositingDependsOnGeometry; - - mutable bool m_compositingNeedsUpdate; + mutable bool m_reevaluateCompositingAfterLayout; bool m_compositing; bool m_compositingLayersNeedRebuild; @@ -337,8 +344,13 @@ private: OwnPtr<GraphicsLayer> m_layerForOverhangAreas; OwnPtr<GraphicsLayer> m_contentShadowLayer; #endif -#if PROFILE_LAYER_REBUILD + +#if !LOG_DISABLED int m_rootLayerUpdateCount; + int m_obligateCompositedLayerCount; // count of layer that have to be composited. + int m_secondaryCompositedLayerCount; // count of layers that have to be composited because of stacking or overlap. + double m_obligatoryBackingAreaMegaPixels; + double m_secondaryBackingAreaMegaPixels; #endif }; diff --git a/Source/WebCore/rendering/RenderLayerFilterInfo.cpp b/Source/WebCore/rendering/RenderLayerFilterInfo.cpp new file mode 100644 index 000000000..703df638c --- /dev/null +++ b/Source/WebCore/rendering/RenderLayerFilterInfo.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(CSS_FILTERS) +#include "RenderLayerFilterInfo.h" + +#include "FilterEffectRenderer.h" +#include "RenderLayer.h" + +#if ENABLE(CSS_SHADERS) +#include "CustomFilterOperation.h" +#include "CustomFilterProgram.h" +#endif + +namespace WebCore { + +RenderLayerFilterInfoMap* RenderLayerFilterInfo::s_filterMap = 0; + +RenderLayerFilterInfo* RenderLayerFilterInfo::filterInfoForRenderLayer(const RenderLayer* layer) +{ + if (!s_filterMap) + return 0; + RenderLayerFilterInfoMap::iterator iter = s_filterMap->find(layer); + return (iter != s_filterMap->end()) ? iter->second : 0; +} + +RenderLayerFilterInfo* RenderLayerFilterInfo::createFilterInfoForRenderLayerIfNeeded(RenderLayer* layer) +{ + if (!s_filterMap) + s_filterMap = new RenderLayerFilterInfoMap(); + + RenderLayerFilterInfoMap::iterator iter = s_filterMap->find(layer); + if (iter != s_filterMap->end()) { + ASSERT(layer->hasFilterInfo()); + return iter->second; + } + + RenderLayerFilterInfo* filter = new RenderLayerFilterInfo(layer); + s_filterMap->set(layer, filter); + layer->setHasFilterInfo(true); + return filter; +} + +void RenderLayerFilterInfo::removeFilterInfoForRenderLayer(RenderLayer* layer) +{ + if (!s_filterMap) + return; + RenderLayerFilterInfo* filter = s_filterMap->take(layer); + if (s_filterMap->isEmpty()) { + delete s_filterMap; + s_filterMap = 0; + } + if (!filter) { + ASSERT(!layer->hasFilterInfo()); + return; + } + layer->setHasFilterInfo(false); + delete filter; +} + +RenderLayerFilterInfo::RenderLayerFilterInfo(RenderLayer* layer) + : m_layer(layer) +{ +} + +RenderLayerFilterInfo::~RenderLayerFilterInfo() +{ +#if ENABLE(CSS_SHADERS) + removeCustomFilterClients(); +#endif +} + +void RenderLayerFilterInfo::setRenderer(PassRefPtr<FilterEffectRenderer> renderer) +{ + m_renderer = renderer; +} + +#if ENABLE(CSS_SHADERS) +void RenderLayerFilterInfo::notifyCustomFilterProgramLoaded(CustomFilterProgram*) +{ + RenderObject* renderer = m_layer->renderer(); + renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange); + renderer->repaint(); +} + +void RenderLayerFilterInfo::updateCustomFilterClients(const FilterOperations& operations) +{ + if (!operations.size()) { + removeCustomFilterClients(); + return; + } + CustomFilterProgramList cachedCustomFilterPrograms; + for (size_t i = 0; i < operations.size(); ++i) { + const FilterOperation* filterOperation = operations.at(i); + if (filterOperation->getOperationType() != FilterOperation::CUSTOM) + continue; + const CustomFilterOperation* customFilterOperation = static_cast<const CustomFilterOperation*>(filterOperation); + RefPtr<CustomFilterProgram> program = customFilterOperation->program(); + cachedCustomFilterPrograms.append(program); + program->addClient(this); + } + // Remove the old clients here, after we've added the new ones, so that we don't flicker if some shaders are unchanged. + removeCustomFilterClients(); + m_cachedCustomFilterPrograms.swap(cachedCustomFilterPrograms); +} + +void RenderLayerFilterInfo::removeCustomFilterClients() +{ + for (size_t i = 0; i < m_cachedCustomFilterPrograms.size(); ++i) + m_cachedCustomFilterPrograms.at(i)->removeClient(this); + m_cachedCustomFilterPrograms.clear(); +} +#endif + +} // namespace WebCore + +#endif // ENABLE(CSS_FILTERS) diff --git a/Source/WebCore/rendering/RenderLayerFilterInfo.h b/Source/WebCore/rendering/RenderLayerFilterInfo.h new file mode 100644 index 000000000..86a9c1393 --- /dev/null +++ b/Source/WebCore/rendering/RenderLayerFilterInfo.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef RenderLayerFilterInfo_h +#define RenderLayerFilterInfo_h + +#if ENABLE(CSS_FILTERS) + +#include "LayoutTypes.h" +#include <wtf/HashMap.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +#if ENABLE(CSS_SHADERS) +#include "CustomFilterProgramClient.h" +#endif + +namespace WebCore { + +class FilterEffectRenderer; +class FilterOperations; +class RenderLayer; +class RenderLayerFilterInfo; + +typedef HashMap<const RenderLayer*, RenderLayerFilterInfo*> RenderLayerFilterInfoMap; + +class RenderLayerFilterInfo +#if ENABLE(CSS_SHADERS) + : public CustomFilterProgramClient +#endif +{ +public: + static RenderLayerFilterInfo* filterInfoForRenderLayer(const RenderLayer*); + static RenderLayerFilterInfo* createFilterInfoForRenderLayerIfNeeded(RenderLayer*); + static void removeFilterInfoForRenderLayer(RenderLayer*); + + const LayoutRect& dirtySourceRect() const { return m_dirtySourceRect; } + void expandDirtySourceRect(const LayoutRect& rect) { m_dirtySourceRect.unite(rect); } + void resetDirtySourceRect() { m_dirtySourceRect = LayoutRect(); } + + FilterEffectRenderer* renderer() const { return m_renderer.get(); } + void setRenderer(PassRefPtr<FilterEffectRenderer>); + +#if ENABLE(CSS_SHADERS) + // Implementation of the CustomFilterProgramClient interface. + virtual void notifyCustomFilterProgramLoaded(CustomFilterProgram*); + + void updateCustomFilterClients(const FilterOperations&); + void removeCustomFilterClients(); +#endif + + +private: + RenderLayerFilterInfo(RenderLayer*); + ~RenderLayerFilterInfo(); + + RenderLayer* m_layer; + + RefPtr<FilterEffectRenderer> m_renderer; + LayoutRect m_dirtySourceRect; + +#if ENABLE(CSS_SHADERS) + typedef Vector<RefPtr<CustomFilterProgram> > CustomFilterProgramList; + CustomFilterProgramList m_cachedCustomFilterPrograms; +#endif + + static RenderLayerFilterInfoMap* s_filterMap; +}; + +} // namespace WebCore + +#endif // ENABLE(CSS_FILTERS) + +#endif // RenderLayerFilterInfo_h diff --git a/Source/WebCore/rendering/RenderLineBoxList.cpp b/Source/WebCore/rendering/RenderLineBoxList.cpp index 6040e0e73..df8a545f3 100644 --- a/Source/WebCore/rendering/RenderLineBoxList.cpp +++ b/Source/WebCore/rendering/RenderLineBoxList.cpp @@ -146,16 +146,16 @@ void RenderLineBoxList::dirtyLineBoxes() curr->dirtyLineBoxes(); } -bool RenderLineBoxList::rangeIntersectsRect(RenderBoxModelObject* renderer, int logicalTop, int logicalBottom, const IntRect& rect, const IntPoint& offset) const +bool RenderLineBoxList::rangeIntersectsRect(RenderBoxModelObject* renderer, LayoutUnit logicalTop, LayoutUnit logicalBottom, const LayoutRect& rect, const LayoutPoint& offset) const { RenderBox* block; if (renderer->isBox()) block = toRenderBox(renderer); else block = renderer->containingBlock(); - int physicalStart = block->flipForWritingMode(logicalTop); - int physicalEnd = block->flipForWritingMode(logicalBottom); - int physicalExtent = abs(physicalEnd - physicalStart); + LayoutUnit physicalStart = block->flipForWritingMode(logicalTop); + LayoutUnit physicalEnd = block->flipForWritingMode(logicalBottom); + LayoutUnit physicalExtent = absoluteValue(physicalEnd - physicalStart); physicalStart = min(physicalStart, physicalEnd); if (renderer->style()->isHorizontalWritingMode()) { @@ -191,11 +191,11 @@ bool RenderLineBoxList::anyLineIntersectsRect(RenderBoxModelObject* renderer, co return rangeIntersectsRect(renderer, logicalTop, logicalBottom, rect, offset); } -bool RenderLineBoxList::lineIntersectsDirtyRect(RenderBoxModelObject* renderer, InlineFlowBox* box, const PaintInfo& paintInfo, const IntPoint& offset) const +bool RenderLineBoxList::lineIntersectsDirtyRect(RenderBoxModelObject* renderer, InlineFlowBox* box, const PaintInfo& paintInfo, const LayoutPoint& offset) const { RootInlineBox* root = box->root(); - int logicalTop = min(box->logicalTopVisualOverflow(root->lineTop()), root->selectionTop()) - renderer->maximalOutlineSize(paintInfo.phase); - int logicalBottom = box->logicalBottomVisualOverflow(root->lineBottom()) + renderer->maximalOutlineSize(paintInfo.phase); + LayoutUnit logicalTop = min<LayoutUnit>(box->logicalTopVisualOverflow(root->lineTop()), root->selectionTop()) - renderer->maximalOutlineSize(paintInfo.phase); + LayoutUnit logicalBottom = box->logicalBottomVisualOverflow(root->lineBottom()) + renderer->maximalOutlineSize(paintInfo.phase); return rangeIntersectsRect(renderer, logicalTop, logicalBottom, paintInfo.rect, offset); } @@ -245,7 +245,7 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintIn if (bottomForPaginationCheck - topForPaginationCheck <= v->printRect().height()) { if (paintOffset.y() + bottomForPaginationCheck > v->printRect().maxY()) { if (RootInlineBox* nextRootBox = curr->root()->nextRootBox()) - bottomForPaginationCheck = min(bottomForPaginationCheck, min(nextRootBox->logicalTopVisualOverflow(), nextRootBox->lineTop())); + bottomForPaginationCheck = min(bottomForPaginationCheck, min<LayoutUnit>(nextRootBox->logicalTopVisualOverflow(), nextRootBox->lineTop())); } if (paintOffset.y() + bottomForPaginationCheck > v->printRect().maxY()) { if (paintOffset.y() + topForPaginationCheck < v->truncatedAt()) @@ -321,9 +321,9 @@ void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, Rend if (!firstBox) { // For an empty inline, go ahead and propagate the check up to our parent, unless the parent // is already dirty. - if (container->isInline() && !container->parent()->selfNeedsLayout()) { + if (container->isInline() && !container->parent()->ancestorLineBoxDirty()) { container->parent()->dirtyLinesFromChangedChild(container); - container->setNeedsLayout(true); // Mark the container as needing layout to avoid dirtying the same lines again across multiple destroy() calls of the same subtree. + container->setAncestorLineBoxDirty(); // Mark the container to avoid dirtying the same lines again across multiple destroy() calls of the same subtree. } return; } @@ -361,9 +361,9 @@ void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, Rend // we won't find a previous sibling, but firstBox can be pointing to a following sibling. // This isn't good enough, since we won't locate the root line box that encloses the removed // <br>. We have to just over-invalidate a bit and go up to our parent. - if (!inlineContainer->parent()->selfNeedsLayout()) { + if (!inlineContainer->parent()->ancestorLineBoxDirty()) { inlineContainer->parent()->dirtyLinesFromChangedChild(inlineContainer); - inlineContainer->setNeedsLayout(true); // Mark the container as needing layout to avoid dirtying the same lines again across multiple destroy() calls of the same subtree. + inlineContainer->setAncestorLineBoxDirty(); // Mark the container to avoid dirtying the same lines again across multiple destroy() calls of the same subtree. } return; } diff --git a/Source/WebCore/rendering/RenderListBox.cpp b/Source/WebCore/rendering/RenderListBox.cpp index e9b0ede36..8cb7d7bb4 100644 --- a/Source/WebCore/rendering/RenderListBox.cpp +++ b/Source/WebCore/rendering/RenderListBox.cpp @@ -32,7 +32,6 @@ #include "AXObjectCache.h" #include "CSSFontSelector.h" -#include "CSSStyleSelector.h" #include "Document.h" #include "DocumentEventQueue.h" #include "EventHandler.h" @@ -58,6 +57,7 @@ #include "Scrollbar.h" #include "ScrollbarTheme.h" #include "SpatialNavigation.h" +#include "StyleResolver.h" #include <math.h> using namespace std; @@ -125,7 +125,7 @@ void RenderListBox::updateFromElement() FontDescription d = itemFont.fontDescription(); d.setWeight(d.bolderWeight()); itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); - itemFont.update(document()->styleSelector()->fontSelector()); + itemFont.update(document()->styleResolver()->fontSelector()); } if (!text.isEmpty()) { @@ -345,7 +345,7 @@ void RenderListBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& void RenderListBox::paintScrollbar(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (m_vBar) { - LayoutRect scrollRect(paintOffset.x() + width() - borderRight() - m_vBar->width(), + IntRect scrollRect = pixelSnappedIntRect(paintOffset.x() + width() - borderRight() - m_vBar->width(), paintOffset.y() + borderTop(), m_vBar->width(), height() - (borderTop() + borderBottom())); @@ -409,7 +409,7 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint& unsigned length = itemText.length(); const UChar* string = itemText.characters(); - TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, itemStyle->direction(), isOverride(itemStyle->unicodeBidi()), TextRun::NoRounding); + TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, itemStyle->direction(), isOverride(itemStyle->unicodeBidi()), true, TextRun::NoRounding); Font itemFont = style()->font(); LayoutRect r = itemBoundingBoxRect(paintOffset, listIndex); r.move(itemOffsetForAlignment(textRun, itemStyle, itemFont, r)); @@ -418,11 +418,11 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, const LayoutPoint& FontDescription d = itemFont.fontDescription(); d.setWeight(d.bolderWeight()); itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); - itemFont.update(document()->styleSelector()->fontSelector()); + itemFont.update(document()->styleResolver()->fontSelector()); } // Draw the item text - paintInfo.context->drawBidiText(itemFont, textRun, r.location()); + paintInfo.context->drawBidiText(itemFont, textRun, roundedIntPoint(r.location())); } void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint& paintOffset, int listIndex) @@ -444,7 +444,7 @@ void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint& ColorSpace colorSpace = element->renderStyle() ? element->renderStyle()->colorSpace() : style()->colorSpace(); LayoutRect itemRect = itemBoundingBoxRect(paintOffset, listIndex); itemRect.intersect(controlClipRect(paintOffset)); - paintInfo.context->fillRect(itemRect, backColor, colorSpace); + paintInfo.context->fillRect(pixelSnappedIntRect(itemRect), backColor, colorSpace); } } @@ -490,7 +490,7 @@ void RenderListBox::panScroll(const IntPoint& panStartMousePosition) // FIXME: This doesn't work correctly with transforms. FloatPoint absOffset = localToAbsolute(); - IntPoint currentMousePosition = roundedIntPoint(frame()->eventHandler()->currentMousePosition()); + IntPoint currentMousePosition = frame()->eventHandler()->currentMousePosition(); // We need to check if the current mouse position is out of the window. When the mouse is out of the window, the position is incoherent static IntPoint previousMousePosition; if (currentMousePosition.y() < 0) diff --git a/Source/WebCore/rendering/RenderListItem.cpp b/Source/WebCore/rendering/RenderListItem.cpp index 6c0677ed8..3e6a7dcae 100644 --- a/Source/WebCore/rendering/RenderListItem.cpp +++ b/Source/WebCore/rendering/RenderListItem.cpp @@ -381,7 +381,7 @@ void RenderListItem::positionListMarker() void RenderListItem::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (!logicalHeight()) + if (!logicalHeight() && hasOverflowClip()) return; RenderBlock::paint(paintInfo, paintOffset); diff --git a/Source/WebCore/rendering/RenderListMarker.cpp b/Source/WebCore/rendering/RenderListMarker.cpp index 8c804549e..0d2f48dd5 100644 --- a/Source/WebCore/rendering/RenderListMarker.cpp +++ b/Source/WebCore/rendering/RenderListMarker.cpp @@ -1090,16 +1090,16 @@ bool RenderListMarker::isImage() const return m_image && !m_image->errorOccurred(); } -IntRect RenderListMarker::localSelectionRect() +LayoutRect RenderListMarker::localSelectionRect() { InlineBox* box = inlineBoxWrapper(); if (!box) - return IntRect(IntPoint(), size()); + return LayoutRect(LayoutPoint(), size()); RootInlineBox* root = m_inlineBoxWrapper->root(); - int newLogicalTop = root->block()->style()->isFlippedBlocksWritingMode() ? m_inlineBoxWrapper->logicalBottom() - root->selectionBottom() : root->selectionTop() - m_inlineBoxWrapper->logicalTop(); + LayoutUnit newLogicalTop = root->block()->style()->isFlippedBlocksWritingMode() ? m_inlineBoxWrapper->logicalBottom() - root->selectionBottom() : root->selectionTop() - m_inlineBoxWrapper->logicalTop(); if (root->block()->style()->isHorizontalWritingMode()) - return IntRect(0, newLogicalTop, width(), root->selectionHeight()); - return IntRect(newLogicalTop, 0, root->selectionHeight(), height()); + return LayoutRect(0, newLogicalTop, width(), root->selectionHeight()); + return LayoutRect(newLogicalTop, 0, root->selectionHeight(), height()); } void RenderListMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) @@ -1110,18 +1110,18 @@ void RenderListMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffse if (style()->visibility() != VISIBLE) return; - IntPoint boxOrigin(paintOffset + location()); + LayoutPoint boxOrigin(paintOffset + location()); LayoutRect overflowRect(visualOverflowRect()); overflowRect.moveBy(boxOrigin); overflowRect.inflate(maximalOutlineSize(paintInfo.phase)); - if (!paintInfo.rect.intersects(overflowRect)) + if (!paintInfo.rect.intersects(pixelSnappedIntRect(overflowRect))) return; - LayoutRect box(boxOrigin, LayoutSize(width(), height())); + LayoutRect box(boxOrigin, size()); - LayoutRect marker = getRelativeMarkerRect(); - marker.moveBy(boxOrigin); + IntRect marker = getRelativeMarkerRect(); + marker.moveBy(roundedIntPoint(boxOrigin)); GraphicsContext* context = paintInfo.context; @@ -1134,7 +1134,7 @@ void RenderListMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffse if (selectionState() != SelectionNone) { LayoutRect selRect = localSelectionRect(); selRect.moveBy(boxOrigin); - context->fillRect(selRect, selectionBackgroundColor(), style()->colorSpace()); + context->fillRect(pixelSnappedIntRect(selRect), selectionBackgroundColor(), style()->colorSpace()); } return; } @@ -1148,7 +1148,7 @@ void RenderListMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffse if (selectionState() != SelectionNone) { LayoutRect selRect = localSelectionRect(); selRect.moveBy(boxOrigin); - context->fillRect(selRect, selectionBackgroundColor(), style()->colorSpace()); + context->fillRect(pixelSnappedIntRect(selRect), selectionBackgroundColor(), style()->colorSpace()); } const Color color(style()->visitedDependentColor(CSSPropertyColor)); @@ -1258,16 +1258,16 @@ void RenderListMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffse GraphicsContextStateSaver stateSaver(*context, false); if (!style()->isHorizontalWritingMode()) { - marker.moveBy(-boxOrigin); + marker.moveBy(roundedIntPoint(-boxOrigin)); marker = marker.transposedRect(); - marker.move(box.x(), box.y() - logicalHeight()); + marker.moveBy(IntPoint(roundToInt(box.x()), roundToInt(box.y() - logicalHeight()))); stateSaver.save(); context->translate(marker.x(), marker.maxY()); context->rotate(static_cast<float>(deg2rad(90.))); context->translate(-marker.x(), -marker.maxY()); } - LayoutPoint textOrigin = LayoutPoint(marker.x(), marker.y() + style()->fontMetrics().ascent()); + IntPoint textOrigin = IntPoint(marker.x(), marker.y() + style()->fontMetrics().ascent()); if (type == Asterisks || type == Footnotes) context->drawText(font, textRun, textOrigin); @@ -1286,14 +1286,14 @@ void RenderListMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffse const UChar suffix = listMarkerSuffix(type, m_listItem->value()); if (style()->isLeftToRightDirection()) { - LayoutUnit width = font.width(textRun); + int width = font.width(textRun); context->drawText(font, textRun, textOrigin); UChar suffixSpace[2] = { suffix, ' ' }; context->drawText(font, RenderBlock::constructTextRun(this, font, suffixSpace, 2, style()), textOrigin + IntSize(width, 0)); } else { UChar spaceSuffix[2] = { ' ', suffix }; TextRun spaceSuffixRun = RenderBlock::constructTextRun(this, font, spaceSuffix, 2, style()); - LayoutUnit width = font.width(spaceSuffixRun); + int width = font.width(spaceSuffixRun); context->drawText(font, spaceSuffixRun, textOrigin); context->drawText(font, textRun, textOrigin + IntSize(width, 0)); } @@ -1349,8 +1349,8 @@ void RenderListMarker::computePreferredLogicalWidths() if (isImage()) { // FIXME: This is a somewhat arbitrary width. Generated images for markers really won't become particularly useful // until we support the CSS3 marker pseudoclass to allow control over the width and height of the marker box. - LayoutUnit bulletWidth = fontMetrics.ascent() / 2; - m_image->setContainerSizeForRenderer(this, LayoutSize(bulletWidth, bulletWidth), style()->effectiveZoom()); + int bulletWidth = fontMetrics.ascent() / 2; + m_image->setContainerSizeForRenderer(this, IntSize(bulletWidth, bulletWidth), style()->effectiveZoom()); LayoutSize imageSize = m_image->imageSize(this, style()->effectiveZoom()); m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = style()->isHorizontalWritingMode() ? imageSize.width() : imageSize.height(); setPreferredLogicalWidthsDirty(false); @@ -1473,8 +1473,8 @@ void RenderListMarker::updateMargins() { const FontMetrics& fontMetrics = style()->fontMetrics(); - int marginStart = 0; - int marginEnd = 0; + LayoutUnit marginStart = 0; + LayoutUnit marginEnd = 0; if (isInside()) { if (isImage()) @@ -1504,7 +1504,7 @@ void RenderListMarker::updateMargins() case NoneListStyle: break; default: - marginStart = m_text.isEmpty() ? 0 : -minPreferredLogicalWidth() - offset / 2; + marginStart = m_text.isEmpty() ? ZERO_LAYOUT_UNIT : -minPreferredLogicalWidth() - offset / 2; } } marginEnd = -marginStart - minPreferredLogicalWidth(); diff --git a/Source/WebCore/rendering/RenderListMarker.h b/Source/WebCore/rendering/RenderListMarker.h index 50e666dbf..d88d922b0 100644 --- a/Source/WebCore/rendering/RenderListMarker.h +++ b/Source/WebCore/rendering/RenderListMarker.h @@ -74,7 +74,7 @@ private: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); IntRect getRelativeMarkerRect(); - IntRect localSelectionRect(); + LayoutRect localSelectionRect(); String m_text; RefPtr<StyleImage> m_image; diff --git a/Source/WebCore/rendering/RenderMarquee.cpp b/Source/WebCore/rendering/RenderMarquee.cpp index fe5dbaa22..db082538f 100644 --- a/Source/WebCore/rendering/RenderMarquee.cpp +++ b/Source/WebCore/rendering/RenderMarquee.cpp @@ -115,8 +115,8 @@ int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge RenderStyle* s = box->style(); if (isHorizontal()) { bool ltr = s->isLeftToRightDirection(); - int clientWidth = box->clientWidth(); - int contentWidth = ltr ? box->maxPreferredLogicalWidth() : box->minPreferredLogicalWidth(); + LayoutUnit clientWidth = box->clientWidth(); + LayoutUnit contentWidth = ltr ? box->maxPreferredLogicalWidth() : box->minPreferredLogicalWidth(); if (ltr) contentWidth += (box->paddingRight() - box->borderLeft()); else { @@ -125,13 +125,13 @@ int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge } if (dir == MRIGHT) { if (stopAtContentEdge) - return max(zeroLayoutUnit, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); + return max(ZERO_LAYOUT_UNIT, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); else return ltr ? contentWidth : clientWidth; } else { if (stopAtContentEdge) - return min(zeroLayoutUnit, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); + return min(ZERO_LAYOUT_UNIT, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); else return ltr ? -clientWidth : -contentWidth; } @@ -289,7 +289,7 @@ void RenderMarquee::timerFired(Timer<RenderMarquee>*) } bool positive = range > 0; int clientSize = (isHorizontal() ? m_layer->renderBox()->clientWidth() : m_layer->renderBox()->clientHeight()); - int increment = abs(m_layer->renderer()->style()->marqueeIncrement().calcValue(clientSize)); + int increment = abs(intValueForLength(m_layer->renderer()->style()->marqueeIncrement(), clientSize)); int currentPos = (isHorizontal() ? m_layer->scrollXOffset() : m_layer->scrollYOffset()); newPos = currentPos + (addIncrement ? increment : -increment); if (positive) diff --git a/Source/WebCore/rendering/RenderMedia.cpp b/Source/WebCore/rendering/RenderMedia.cpp index be4adde7b..9af648b02 100644 --- a/Source/WebCore/rendering/RenderMedia.cpp +++ b/Source/WebCore/rendering/RenderMedia.cpp @@ -77,13 +77,17 @@ void RenderMedia::layout() controlsRenderer->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop())); controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed)); controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed)); - controlsRenderer->setNeedsLayout(true, false); + controlsRenderer->setNeedsLayout(true, MarkOnlyThis); controlsRenderer->layout(); setChildNeedsLayout(false); statePusher.pop(); } +void RenderMedia::paintReplaced(PaintInfo&, const LayoutPoint&) +{ +} + } // namespace WebCore #endif diff --git a/Source/WebCore/rendering/RenderMedia.h b/Source/WebCore/rendering/RenderMedia.h index 54e625af3..abcc3b64b 100644 --- a/Source/WebCore/rendering/RenderMedia.h +++ b/Source/WebCore/rendering/RenderMedia.h @@ -56,6 +56,7 @@ private: virtual const char* renderName() const { return "RenderMedia"; } virtual bool isMedia() const { return true; } virtual bool isImage() const { return false; } + virtual void paintReplaced(PaintInfo&, const LayoutPoint&); virtual bool requiresForcedStyleRecalcPropagation() const { return true; } diff --git a/Source/WebCore/rendering/RenderMediaControls.cpp b/Source/WebCore/rendering/RenderMediaControls.cpp index f791274e7..3ecd86748 100644 --- a/Source/WebCore/rendering/RenderMediaControls.cpp +++ b/Source/WebCore/rendering/RenderMediaControls.cpp @@ -119,83 +119,87 @@ bool RenderMediaControls::paintMediaControlsPart(MediaControlElementType part, R GraphicsContextStateSaver stateSaver(*paintInfo.context); switch (part) { - case MediaFullscreenButton: - wkDrawMediaUIPart(WKMediaUIPartFullscreenButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - break; - case MediaShowClosedCaptionsButton: - case MediaHideClosedCaptionsButton: - if (MediaControlToggleClosedCaptionsButtonElement* btn = static_cast<MediaControlToggleClosedCaptionsButtonElement*>(o->node())) { - bool captionsVisible = btn->displayType() == MediaHideClosedCaptionsButton; - wkDrawMediaUIPart(captionsVisible ? WKMediaUIPartHideClosedCaptionsButton : WKMediaUIPartShowClosedCaptionsButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - } - break; - case MediaMuteButton: - case MediaUnMuteButton: - if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(o->node())) { - bool audioEnabled = btn->displayType() == MediaMuteButton; - 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; - 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 MediaReturnToRealtimeButton: - wkDrawMediaUIPart(WKMediaUIPartSeekToRealtimeButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - break; - case MediaSeekBackButton: - wkDrawMediaUIPart(WKMediaUIPartSeekBackButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - break; - case MediaSeekForwardButton: - wkDrawMediaUIPart(WKMediaUIPartSeekForwardButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - break; - case MediaSlider: { - 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 MediaEnterFullscreenButton: + case MediaExitFullscreenButton: + if (MediaControlFullscreenButtonElement* btn = static_cast<MediaControlFullscreenButtonElement*>(o->node())) { + bool enterButton = btn->displayType() == MediaEnterFullscreenButton; + wkDrawMediaUIPart(enterButton ? WKMediaUIPartFullscreenButton : WKMediaUIPartExitFullscreenButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); } - case MediaSliderThumb: - wkDrawMediaUIPart(WKMediaUIPartTimelineSliderThumb, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - break; - case MediaVolumeSliderContainer: - wkDrawMediaUIPart(WKMediaUIPartVolumeSliderContainer, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - break; - case MediaVolumeSlider: - wkDrawMediaUIPart(WKMediaUIPartVolumeSlider, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - break; - case MediaVolumeSliderThumb: - wkDrawMediaUIPart(WKMediaUIPartVolumeSliderThumb, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - break; - case MediaFullScreenVolumeSlider: - wkDrawMediaUIPart(WKMediaUIPartFullScreenVolumeSlider, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - break; - case MediaFullScreenVolumeSliderThumb: - wkDrawMediaUIPart(WKMediaUIPartFullScreenVolumeSliderThumb, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - break; - case MediaTimelineContainer: - wkDrawMediaUIPart(WKMediaUIPartBackground, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); - break; - case MediaCurrentTimeDisplay: - ASSERT_NOT_REACHED(); - break; - case MediaTimeRemainingDisplay: - ASSERT_NOT_REACHED(); - break; - case MediaControlsPanel: - ASSERT_NOT_REACHED(); - case MediaTextTrackDisplayContainer: - case MediaTextTrackDisplay: - ASSERT_NOT_REACHED(); - break; + break; + case MediaShowClosedCaptionsButton: + case MediaHideClosedCaptionsButton: + if (MediaControlToggleClosedCaptionsButtonElement* btn = static_cast<MediaControlToggleClosedCaptionsButtonElement*>(o->node())) { + bool captionsVisible = btn->displayType() == MediaHideClosedCaptionsButton; + wkDrawMediaUIPart(captionsVisible ? WKMediaUIPartHideClosedCaptionsButton : WKMediaUIPartShowClosedCaptionsButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); + } + break; + case MediaMuteButton: + case MediaUnMuteButton: + if (MediaControlMuteButtonElement* btn = static_cast<MediaControlMuteButtonElement*>(o->node())) { + bool audioEnabled = btn->displayType() == MediaMuteButton; + 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; + 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 MediaReturnToRealtimeButton: + wkDrawMediaUIPart(WKMediaUIPartSeekToRealtimeButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); + break; + case MediaSeekBackButton: + wkDrawMediaUIPart(WKMediaUIPartSeekBackButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); + break; + case MediaSeekForwardButton: + wkDrawMediaUIPart(WKMediaUIPartSeekForwardButton, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); + break; + case MediaSlider: { + 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: + wkDrawMediaUIPart(WKMediaUIPartTimelineSliderThumb, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); + break; + case MediaVolumeSliderContainer: + wkDrawMediaUIPart(WKMediaUIPartVolumeSliderContainer, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); + break; + case MediaVolumeSlider: + wkDrawMediaUIPart(WKMediaUIPartVolumeSlider, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); + break; + case MediaVolumeSliderThumb: + wkDrawMediaUIPart(WKMediaUIPartVolumeSliderThumb, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); + break; + case MediaFullScreenVolumeSlider: + wkDrawMediaUIPart(WKMediaUIPartFullScreenVolumeSlider, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); + break; + case MediaFullScreenVolumeSliderThumb: + wkDrawMediaUIPart(WKMediaUIPartFullScreenVolumeSliderThumb, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); + break; + case MediaTimelineContainer: + wkDrawMediaUIPart(WKMediaUIPartBackground, themeStyle, paintInfo.context->platformContext(), r, determineState(o)); + break; + case MediaCurrentTimeDisplay: + ASSERT_NOT_REACHED(); + break; + case MediaTimeRemainingDisplay: + ASSERT_NOT_REACHED(); + break; + case MediaControlsPanel: + ASSERT_NOT_REACHED(); + case MediaTextTrackDisplayContainer: + case MediaTextTrackDisplay: + ASSERT_NOT_REACHED(); + break; +} return false; } @@ -208,10 +212,10 @@ IntPoint RenderMediaControls::volumeSliderOffsetFromMuteButton(RenderBox* muteBu static const int yOffset = 5; float zoomLevel = muteButtonBox->style()->effectiveZoom(); - int y = yOffset * zoomLevel + muteButtonBox->offsetHeight() - size.height(); - FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->offsetLeft(), y), true, true); + int y = yOffset * zoomLevel + muteButtonBox->pixelSnappedOffsetHeight() - size.height(); + FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->pixelSnappedOffsetLeft(), y), true, true); if (absPoint.y() < 0) - y = muteButtonBox->height(); + y = muteButtonBox->pixelSnappedHeight(); return IntPoint(xOffset * zoomLevel, y); } diff --git a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp b/Source/WebCore/rendering/RenderMediaControlsChromium.cpp index 66b088260..89383c0d1 100644 --- a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp +++ b/Source/WebCore/rendering/RenderMediaControlsChromium.cpp @@ -267,7 +267,8 @@ bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType return paintMediaVolumeSliderThumb(object, paintInfo, rect); case MediaTimelineContainer: return paintMediaTimelineContainer(object, paintInfo, rect); - case MediaFullscreenButton: + case MediaEnterFullscreenButton: + case MediaExitFullscreenButton: return paintMediaFullscreenButton(object, paintInfo, rect); case MediaVolumeSliderMuteButton: case MediaSeekBackButton: diff --git a/Source/WebCore/rendering/RenderMenuList.cpp b/Source/WebCore/rendering/RenderMenuList.cpp index a47aebbae..6d25c3572 100644 --- a/Source/WebCore/rendering/RenderMenuList.cpp +++ b/Source/WebCore/rendering/RenderMenuList.cpp @@ -28,7 +28,6 @@ #include "AXObjectCache.h" #include "AccessibilityMenuList.h" #include "CSSFontSelector.h" -#include "CSSStyleSelector.h" #include "Chrome.h" #include "FontCache.h" #include "Frame.h" @@ -43,6 +42,8 @@ #include "RenderBR.h" #include "RenderScrollbar.h" #include "RenderTheme.h" +#include "Settings.h" +#include "StyleResolver.h" #include "TextRun.h" #include <math.h> @@ -161,7 +162,7 @@ void RenderMenuList::updateOptionsWidth() // Add in the option's text indent. We can't calculate percentage values for now. float optionWidth = 0; if (RenderStyle* optionStyle = element->renderStyle()) - optionWidth += optionStyle->textIndent().calcMinValue(0); + optionWidth += minimumValueForLength(optionStyle->textIndent(), 0, view()); if (!text.isEmpty()) optionWidth += style()->font().width(text); maxOptionWidth = max(maxOptionWidth, optionWidth); @@ -307,8 +308,11 @@ void RenderMenuList::showPopup() // Compute the top left taking transforms into account, but use // the actual width of the element to size the popup. FloatPoint absTopLeft = localToAbsolute(FloatPoint(), false, true); - LayoutRect absBounds = absoluteBoundingBoxRectIgnoringTransforms(); - absBounds.setLocation(roundedLayoutPoint(absTopLeft)); + IntRect absBounds = absoluteBoundingBoxRectIgnoringTransforms(); + int scale = document()->page()->settings()->defaultDeviceScaleFactor(); + if (scale && scale != 1) + absBounds.scale(scale); + absBounds.setLocation(roundedIntPoint(absTopLeft)); HTMLSelectElement* select = toHTMLSelectElement(node()); m_popup->show(absBounds, document()->view(), select->optionToListIndex(select->selectedIndex())); } @@ -507,13 +511,13 @@ int RenderMenuList::clientInsetRight() const return 0; } -int RenderMenuList::clientPaddingLeft() const +LayoutUnit RenderMenuList::clientPaddingLeft() const { return paddingLeft() + m_innerBlock->paddingLeft(); } const int endOfLinePadding = 2; -int RenderMenuList::clientPaddingRight() const +LayoutUnit RenderMenuList::clientPaddingRight() const { if (style()->appearance() == MenulistPart || style()->appearance() == MenulistButtonPart) { // For these appearance values, the theme applies padding to leave room for the @@ -572,7 +576,7 @@ void RenderMenuList::setTextFromItem(unsigned listIndex) FontSelector* RenderMenuList::fontSelector() const { - return document()->styleSelector()->fontSelector(); + return document()->styleResolver()->fontSelector(); } } diff --git a/Source/WebCore/rendering/RenderMeter.cpp b/Source/WebCore/rendering/RenderMeter.cpp index 78ed8cdeb..5540a1942 100644 --- a/Source/WebCore/rendering/RenderMeter.cpp +++ b/Source/WebCore/rendering/RenderMeter.cpp @@ -46,13 +46,13 @@ RenderMeter::~RenderMeter() void RenderMeter::computeLogicalWidth() { RenderBox::computeLogicalWidth(); - setWidth(theme()->meterSizeForBounds(this, frameRect()).width()); + setWidth(theme()->meterSizeForBounds(this, pixelSnappedIntRect(frameRect())).width()); } void RenderMeter::computeLogicalHeight() { RenderBox::computeLogicalHeight(); - setHeight(theme()->meterSizeForBounds(this, frameRect()).height()); + setHeight(theme()->meterSizeForBounds(this, pixelSnappedIntRect(frameRect())).height()); } double RenderMeter::valueRatio() const diff --git a/Source/WebCore/rendering/RenderMultiColumnBlock.cpp b/Source/WebCore/rendering/RenderMultiColumnBlock.cpp new file mode 100644 index 000000000..d29055e68 --- /dev/null +++ b/Source/WebCore/rendering/RenderMultiColumnBlock.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderMultiColumnBlock.h" + +using namespace std; + +namespace WebCore { + +RenderMultiColumnBlock::RenderMultiColumnBlock(Node* node) + : RenderBlock(node) + , m_columnCount(1) + , m_columnWidth(0) +{ +} + +void RenderMultiColumnBlock::computeColumnCountAndWidth() +{ + // Calculate our column width and column count. + // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744 + m_columnCount = 1; + m_columnWidth = contentLogicalWidth(); + + ASSERT(!style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth()); + + LayoutUnit availWidth = m_columnWidth; + LayoutUnit colGap = columnGap(); + LayoutUnit colWidth = max<LayoutUnit>(1, LayoutUnit(style()->columnWidth())); + int colCount = max<int>(1, style()->columnCount()); + + if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) { + m_columnCount = colCount; + m_columnWidth = max<LayoutUnit>(0, (availWidth - ((m_columnCount - 1) * colGap)) / m_columnCount); + } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) { + m_columnCount = max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap)); + m_columnWidth = ((availWidth + colGap) / m_columnCount) - colGap; + } else { + m_columnCount = max<LayoutUnit>(min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1); + m_columnWidth = ((availWidth + colGap) / m_columnCount) - colGap; + } +} + +bool RenderMultiColumnBlock::recomputeLogicalWidth() +{ + bool relayoutChildren = RenderBlock::recomputeLogicalWidth(); + LayoutUnit oldColumnWidth = m_columnWidth; + computeColumnCountAndWidth(); + if (m_columnWidth != oldColumnWidth) + relayoutChildren = true; + return relayoutChildren; +} + +const char* RenderMultiColumnBlock::renderName() const +{ + if (isFloating()) + return "RenderMultiColumnBlock (floating)"; + if (isPositioned()) + return "RenderMultiColumnBlock (positioned)"; + if (isAnonymousBlock()) + return "RenderMultiColumnBlock (anonymous)"; + if (isAnonymous()) + return "RenderMultiColumnBlock (generated)"; + if (isRelPositioned()) + return "RenderMultiColumnBlock (relative positioned)"; + return "RenderMultiColumnBlock"; +} + +} diff --git a/Source/WebCore/rendering/RenderMultiColumnBlock.h b/Source/WebCore/rendering/RenderMultiColumnBlock.h new file mode 100644 index 000000000..2ab642146 --- /dev/null +++ b/Source/WebCore/rendering/RenderMultiColumnBlock.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef RenderMultiColumnBlock_h +#define RenderMultiColumnBlock_h + +#include "RenderBlock.h" + +namespace WebCore { + +class RenderMultiColumnBlock : public RenderBlock { +public: + RenderMultiColumnBlock(Node*); + +private: + virtual const char* renderName() const; + + virtual bool recomputeLogicalWidth(); + void computeColumnCountAndWidth(); + +private: + unsigned m_columnCount; // The default column count/width that are based off our containing block width. These values represent only the default, + LayoutUnit m_columnWidth; // since a multi-column block that is split across variable width pages or regions will have different column counts and widths in each. + // These values will be cached (eventually) for multi-column blocks. +}; + +} // namespace WebCore + +#endif // RenderMultiColumnBlock_h + diff --git a/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp b/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp new file mode 100644 index 000000000..e90ef4e3c --- /dev/null +++ b/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS IN..0TERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderMultiColumnFlowThread.h" + +namespace WebCore { + +RenderMultiColumnFlowThread::RenderMultiColumnFlowThread(Node* node) + : RenderFlowThread(node) +{ +} + +const char* RenderMultiColumnFlowThread::renderName() const +{ + return "RenderMultiColumnFlowThread"; +} + +} diff --git a/Source/WebCore/rendering/RenderMultiColumnFlowThread.h b/Source/WebCore/rendering/RenderMultiColumnFlowThread.h new file mode 100644 index 000000000..f4a0a0420 --- /dev/null +++ b/Source/WebCore/rendering/RenderMultiColumnFlowThread.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef RenderMultiColumnFlowThread_h +#define RenderMultiColumnFlowThread_h + +#include "RenderFlowThread.h" + +namespace WebCore { + +class RenderMultiColumnFlowThread : public RenderFlowThread { +public: + RenderMultiColumnFlowThread(Node*); + +private: + virtual const char* renderName() const OVERRIDE; +}; + +} // namespace WebCore + +#endif // RenderMultiColumnFlowThread_h + diff --git a/Source/WebCore/rendering/RenderMultiColumnSet.cpp b/Source/WebCore/rendering/RenderMultiColumnSet.cpp new file mode 100644 index 000000000..437aa4264 --- /dev/null +++ b/Source/WebCore/rendering/RenderMultiColumnSet.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderMultiColumnSet.h" + +namespace WebCore { + +RenderMultiColumnSet::RenderMultiColumnSet(Node* node, RenderFlowThread* flowThread) + : RenderRegionSet(node, flowThread) +{ +} + +const char* RenderMultiColumnSet::renderName() const +{ + return "RenderMultiColumnSet"; +} + +} diff --git a/Source/WebCore/rendering/RenderMultiColumnSet.h b/Source/WebCore/rendering/RenderMultiColumnSet.h new file mode 100644 index 000000000..c5794c8df --- /dev/null +++ b/Source/WebCore/rendering/RenderMultiColumnSet.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef RenderMultiColumnSet_h +#define RenderMultiColumnSet_h + +#include "RenderRegionSet.h" + +namespace WebCore { + +// RenderMultiColumnSet represents a set of columns that all have the same width and height. By combining runs of same-size columns into a single +// object, we significantly reduce the number of unique RenderObjects required to represent columns. +// +// A simple multi-column block will have exactly one RenderMultiColumnSet child. A simple paginated multi-column block will have three +// RenderMultiColumnSet children: one for the content at the bottom of the first page (whose columns will have a shorter height), one +// for the 2nd to n-1 pages, and then one last column set that will hold the shorter columns on the final page (that may have to be balanced +// as well). +// +// Column spans result in the creation of new column sets as well, since a spanning region has to be placed in between the column sets that +// come before and after the span. +class RenderMultiColumnSet : public RenderRegionSet { +public: + RenderMultiColumnSet(Node*, RenderFlowThread*); + +private: + virtual const char* renderName() const; +}; + +} // namespace WebCore + +#endif // RenderMultiColumnSet_h + diff --git a/Source/WebCore/rendering/RenderNamedFlowThread.cpp b/Source/WebCore/rendering/RenderNamedFlowThread.cpp new file mode 100644 index 000000000..088b87248 --- /dev/null +++ b/Source/WebCore/rendering/RenderNamedFlowThread.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS IN..0TERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderNamedFlowThread.h" + +#include "FlowThreadController.h" +#include "RenderRegion.h" +#include "RenderView.h" +#include "WebKitNamedFlow.h" + +namespace WebCore { + +RenderNamedFlowThread::RenderNamedFlowThread(Node* node, const AtomicString& name) + : RenderFlowThread(node) + , m_flowThreadName(name) +{ +} + +const char* RenderNamedFlowThread::renderName() const +{ + return "RenderNamedFlowThread"; +} + + +RenderObject* RenderNamedFlowThread::nextRendererForNode(Node* node) const +{ + FlowThreadChildList::const_iterator it = m_flowThreadChildList.begin(); + FlowThreadChildList::const_iterator end = m_flowThreadChildList.end(); + + for (; it != end; ++it) { + RenderObject* child = *it; + ASSERT(child->node()); + unsigned short position = node->compareDocumentPosition(child->node()); + if (position & Node::DOCUMENT_POSITION_FOLLOWING) + return child; + } + + return 0; +} + +RenderObject* RenderNamedFlowThread::previousRendererForNode(Node* node) const +{ + if (m_flowThreadChildList.isEmpty()) + return 0; + + FlowThreadChildList::const_iterator begin = m_flowThreadChildList.begin(); + FlowThreadChildList::const_iterator end = m_flowThreadChildList.end(); + FlowThreadChildList::const_iterator it = end; + + do { + --it; + RenderObject* child = *it; + ASSERT(child->node()); + unsigned short position = node->compareDocumentPosition(child->node()); + if (position & Node::DOCUMENT_POSITION_PRECEDING) + return child; + } while (it != begin); + + return 0; +} + +void RenderNamedFlowThread::addFlowChild(RenderObject* newChild, RenderObject* beforeChild) +{ + // The child list is used to sort the flow thread's children render objects + // based on their corresponding nodes DOM order. The list is needed to avoid searching the whole DOM. + + // Do not add anonymous objects. + if (!newChild->node()) + return; + + if (beforeChild) + m_flowThreadChildList.insertBefore(beforeChild, newChild); + else + m_flowThreadChildList.add(newChild); +} + +void RenderNamedFlowThread::removeFlowChild(RenderObject* child) +{ + m_flowThreadChildList.remove(child); +} + +bool RenderNamedFlowThread::dependsOn(RenderNamedFlowThread* otherRenderFlowThread) const +{ + if (m_layoutBeforeThreadsSet.contains(otherRenderFlowThread)) + return true; + + // Recursively traverse the m_layoutBeforeThreadsSet. + RenderNamedFlowThreadCountedSet::const_iterator iterator = m_layoutBeforeThreadsSet.begin(); + RenderNamedFlowThreadCountedSet::const_iterator end = m_layoutBeforeThreadsSet.end(); + for (; iterator != end; ++iterator) { + const RenderNamedFlowThread* beforeFlowThread = (*iterator).first; + if (beforeFlowThread->dependsOn(otherRenderFlowThread)) + return true; + } + + return false; +} + +// Compare two regions to determine in which one the content should flow first. +// The function returns true if the first passed region is "less" than the second passed region. +// If the first region appears before second region in DOM, +// the first region is "less" than the second region. +// If the first region is "less" than the second region, the first region receives content before second region. +static bool compareRenderRegions(const RenderRegion* firstRegion, const RenderRegion* secondRegion) +{ + ASSERT(firstRegion); + ASSERT(secondRegion); + + // If the regions have the same region-index, compare their position in dom. + ASSERT(firstRegion->node()); + ASSERT(secondRegion->node()); + + unsigned short position = firstRegion->node()->compareDocumentPosition(secondRegion->node()); + return (position & Node::DOCUMENT_POSITION_FOLLOWING); +} + +void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion) +{ + ASSERT(renderRegion); + if (m_regionList.isEmpty()) + m_regionList.add(renderRegion); + else { + // Find the first region "greater" than renderRegion. + RenderRegionList::iterator it = m_regionList.begin(); + while (it != m_regionList.end() && !compareRenderRegions(renderRegion, *it)) + ++it; + m_regionList.insertBefore(it, renderRegion); + } + + ASSERT(!renderRegion->isValid()); + if (renderRegion->parentNamedFlowThread()) { + if (renderRegion->parentNamedFlowThread()->dependsOn(this)) { + // Register ourself to get a notification when the state changes. + renderRegion->parentNamedFlowThread()->m_observerThreadsSet.add(this); + return; + } + + addDependencyOnFlowThread(renderRegion->parentNamedFlowThread()); + } + + renderRegion->setIsValid(true); + + invalidateRegions(); +} + +void RenderNamedFlowThread::removeRegionFromThread(RenderRegion* renderRegion) +{ + ASSERT(renderRegion); + m_regionRangeMap.clear(); + m_regionList.remove(renderRegion); + + if (renderRegion->parentNamedFlowThread()) { + if (!renderRegion->isValid()) { + renderRegion->parentNamedFlowThread()->m_observerThreadsSet.remove(this); + // No need to invalidate the regions rectangles. The removed region + // was not taken into account. Just return here. + return; + } + removeDependencyOnFlowThread(renderRegion->parentNamedFlowThread()); + } + + invalidateRegions(); +} + + +void RenderNamedFlowThread::checkInvalidRegions() +{ + for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { + RenderRegion* region = *iter; + // The only reason a region would be invalid is because it has a parent flow thread. + ASSERT(region->isValid() || region->parentNamedFlowThread()); + if (region->isValid() || region->parentNamedFlowThread()->dependsOn(this)) + continue; + + region->parentNamedFlowThread()->m_observerThreadsSet.remove(this); + addDependencyOnFlowThread(region->parentNamedFlowThread()); + region->setIsValid(true); + invalidateRegions(); + } + + if (m_observerThreadsSet.isEmpty()) + return; + + // Notify all the flow threads that were dependent on this flow. + + // Create a copy of the list first. That's because observers might change the list when calling checkInvalidRegions. + Vector<RenderNamedFlowThread*> observers; + copyToVector(m_observerThreadsSet, observers); + + for (size_t i = 0; i < observers.size(); ++i) { + RenderNamedFlowThread* flowThread = observers.at(i); + flowThread->checkInvalidRegions(); + } +} + +void RenderNamedFlowThread::addDependencyOnFlowThread(RenderNamedFlowThread* otherFlowThread) +{ + RenderNamedFlowThreadCountedSet::AddResult result = m_layoutBeforeThreadsSet.add(otherFlowThread); + if (result.isNewEntry) { + // This is the first time we see this dependency. Make sure we recalculate all the dependencies. + view()->flowThreadController()->setIsRenderNamedFlowThreadOrderDirty(true); + } +} + +void RenderNamedFlowThread::removeDependencyOnFlowThread(RenderNamedFlowThread* otherFlowThread) +{ + bool removed = m_layoutBeforeThreadsSet.remove(otherFlowThread); + if (removed) { + checkInvalidRegions(); + view()->flowThreadController()->setIsRenderNamedFlowThreadOrderDirty(true); + } +} + +void RenderNamedFlowThread::pushDependencies(RenderNamedFlowThreadList& list) +{ + for (RenderNamedFlowThreadCountedSet::iterator iter = m_layoutBeforeThreadsSet.begin(); iter != m_layoutBeforeThreadsSet.end(); ++iter) { + RenderNamedFlowThread* flowThread = (*iter).first; + if (list.contains(flowThread)) + continue; + flowThread->pushDependencies(list); + list.add(flowThread); + } +} + +WebKitNamedFlow* RenderNamedFlowThread::ensureNamedFlow() +{ + if (!m_namedFlow) + m_namedFlow = WebKitNamedFlow::create(this); + + return m_namedFlow.get(); +} + +// The content nodes list contains those nodes with -webkit-flow-into: flow. +// An element with display:none should also be listed among those nodes. +// The list of nodes is ordered. +void RenderNamedFlowThread::registerNamedFlowContentNode(Node* contentNode) +{ + ASSERT(contentNode && contentNode->isElementNode()); + + contentNode->setInNamedFlow(); + + // Find the first content node following the new content node. + for (NamedFlowContentNodes::iterator it = m_contentNodes.begin(); it != m_contentNodes.end(); ++it) { + Node* node = *it; + unsigned short position = contentNode->compareDocumentPosition(node); + if (position & Node::DOCUMENT_POSITION_FOLLOWING) { + m_contentNodes.insertBefore(node, contentNode); + return; + } + } + m_contentNodes.add(contentNode); +} + +void RenderNamedFlowThread::unregisterNamedFlowContentNode(Node* contentNode) +{ + ASSERT(contentNode && contentNode->isElementNode()); + ASSERT(m_contentNodes.contains(contentNode)); + ASSERT(contentNode->inNamedFlow()); + + contentNode->clearInNamedFlow(); + m_contentNodes.remove(contentNode); + +} + +} diff --git a/Source/WebCore/rendering/RenderNamedFlowThread.h b/Source/WebCore/rendering/RenderNamedFlowThread.h new file mode 100644 index 000000000..d0c8ca014 --- /dev/null +++ b/Source/WebCore/rendering/RenderNamedFlowThread.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef RenderNamedFlowThread_h +#define RenderNamedFlowThread_h + +#include "RenderFlowThread.h" +#include <wtf/HashCountedSet.h> +#include <wtf/ListHashSet.h> +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +class Node; +class RenderNamedFlowThread; +class WebKitNamedFlow; + +typedef ListHashSet<RenderNamedFlowThread*> RenderNamedFlowThreadList; +typedef HashCountedSet<RenderNamedFlowThread*> RenderNamedFlowThreadCountedSet; +typedef ListHashSet<Node*> NamedFlowContentNodes; + +class RenderNamedFlowThread : public RenderFlowThread { +public: + RenderNamedFlowThread(Node*, const AtomicString&); + + AtomicString flowThreadName() const { return m_flowThreadName; } + + RenderObject* nextRendererForNode(Node*) const; + RenderObject* previousRendererForNode(Node*) const; + + void addFlowChild(RenderObject* newChild, RenderObject* beforeChild = 0); + void removeFlowChild(RenderObject*); + bool hasChildren() const { return !m_flowThreadChildList.isEmpty(); } +#ifndef NDEBUG + bool hasChild(RenderObject* child) const { return m_flowThreadChildList.contains(child); } +#endif + + void pushDependencies(RenderNamedFlowThreadList&); + + virtual void addRegionToThread(RenderRegion*) OVERRIDE; + virtual void removeRegionFromThread(RenderRegion*) OVERRIDE; + + WebKitNamedFlow* ensureNamedFlow(); + void registerNamedFlowContentNode(Node*); + void unregisterNamedFlowContentNode(Node*); + const NamedFlowContentNodes& contentNodes() const { return m_contentNodes; } + bool hasContentNode(Node* contentNode) const { ASSERT(contentNode); return m_contentNodes.contains(contentNode); } + +private: + virtual const char* renderName() const OVERRIDE; + virtual bool isRenderNamedFlowThread() const OVERRIDE { return true; } + + bool dependsOn(RenderNamedFlowThread* otherRenderFlowThread) const; + void addDependencyOnFlowThread(RenderNamedFlowThread*); + void removeDependencyOnFlowThread(RenderNamedFlowThread*); + void checkInvalidRegions(); + +private: + // The name of the flow thread as specified in CSS. + AtomicString m_flowThreadName; + + // Observer flow threads have invalid regions that depend on the state of this thread + // to re-validate their regions. Keeping a set of observer threads make it easy + // to notify them when a region was removed from this flow. + RenderNamedFlowThreadCountedSet m_observerThreadsSet; + + // Some threads need to have a complete layout before we layout this flow. + // That's because they contain a RenderRegion that should display this thread. The set makes it + // easy to sort the order of threads layout. + RenderNamedFlowThreadCountedSet m_layoutBeforeThreadsSet; + + // Holds the sorted children of a named flow. This is the only way we can get the ordering right. + typedef ListHashSet<RenderObject*> FlowThreadChildList; + FlowThreadChildList m_flowThreadChildList; + + NamedFlowContentNodes m_contentNodes; + + // The DOM Object that represents a named flow. + RefPtr<WebKitNamedFlow> m_namedFlow; +}; + +inline RenderNamedFlowThread* toRenderNamedFlowThread(RenderObject* object) +{ + ASSERT(!object || object->isRenderNamedFlowThread()); + return static_cast<RenderNamedFlowThread*>(object); +} + +inline const RenderNamedFlowThread* toRenderNamedFlowThread(const RenderObject* object) +{ + ASSERT(!object || object->isRenderNamedFlowThread()); + return static_cast<const RenderNamedFlowThread*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderNamedFlowThread(const RenderNamedFlowThread*); + +} // namespace WebCore + +#endif // RenderNamedFlowThread_h + diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp index fbe452577..cc80bae9b 100755 --- a/Source/WebCore/rendering/RenderObject.cpp +++ b/Source/WebCore/rendering/RenderObject.cpp @@ -28,13 +28,13 @@ #include "RenderObject.h" #include "AXObjectCache.h" -#include "CSSStyleSelector.h" #include "Chrome.h" #include "ContentData.h" #include "CursorList.h" #include "DashArray.h" #include "EditingBoundary.h" #include "FloatQuad.h" +#include "FlowThreadController.h" #include "Frame.h" #include "FrameView.h" #include "GraphicsContext.h" @@ -46,12 +46,13 @@ #include "RenderCounter.h" #include "RenderDeprecatedFlexibleBox.h" #include "RenderFlexibleBox.h" -#include "RenderFlowThread.h" #include "RenderImage.h" #include "RenderImageResourceStyleImage.h" #include "RenderInline.h" #include "RenderLayer.h" #include "RenderListItem.h" +#include "RenderMultiColumnBlock.h" +#include "RenderNamedFlowThread.h" #include "RenderRegion.h" #include "RenderRuby.h" #include "RenderRubyText.h" @@ -61,6 +62,8 @@ #include "RenderTableRow.h" #include "RenderTheme.h" #include "RenderView.h" +#include "Settings.h" +#include "StyleResolver.h" #include "TransformState.h" #include "htmlediting.h" #include <algorithm> @@ -100,6 +103,8 @@ COMPILE_ASSERT(sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), RenderObj bool RenderObject::s_affectsParentBlock = false; +RenderObjectAncestorLineboxDirtySet* RenderObject::s_ancestorLineboxDirtySet = 0; + void* RenderObject::operator new(size_t sz, RenderArena* renderArena) { return renderArena->allocate(sz); @@ -159,7 +164,9 @@ RenderObject* RenderObject::createObject(Node* node, RenderStyle* style) case COMPACT: // Only non-replaced block elements can become a region. if (doc->cssRegionsEnabled() && !style->regionThread().isEmpty() && doc->renderView()) - return new (arena) RenderRegion(node, doc->renderView()->ensureRenderFlowThreadWithName(style->regionThread())); + return new (arena) RenderRegion(node, doc->renderView()->flowThreadController()->ensureRenderFlowThreadWithName(style->regionThread())); + if ((!style->hasAutoColumnCount() || !style->hasAutoColumnWidth()) && doc->regionBasedColumnsEnabled()) + return new (arena) RenderMultiColumnBlock(node); return new (arena) RenderBlock(node); case LIST_ITEM: return new (arena) RenderListItem(node); @@ -256,26 +263,6 @@ bool RenderObject::isHTMLMarquee() const return node() && node()->renderer() == this && node()->hasTagName(marqueeTag); } -static bool isBeforeAfterContentGeneratedByAncestor(RenderObject* renderer, RenderObject* beforeAfterContent) -{ - while (renderer) { - if (renderer->generatingNode() == beforeAfterContent->generatingNode()) - return true; - renderer = renderer->parent(); - } - return false; -} - -RenderTable* RenderObject::createAnonymousTable() const -{ - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); - newStyle->setDisplay(TABLE); - - RenderTable* table = new (renderArena()) RenderTable(document() /* is anonymous */); - table->setStyle(newStyle.release()); - return table; -} - void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) { RenderObjectChildList* children = virtualChildren(); @@ -283,17 +270,6 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) if (!children) return; - RenderObject* beforeContent = 0; - bool beforeChildHasBeforeAndAfterContent = false; - if (beforeChild && (beforeChild->isTable() || beforeChild->isTableSection() || beforeChild->isTableRow() || beforeChild->isTableCell())) { - beforeContent = beforeChild->beforePseudoElementRenderer(); - RenderObject* afterContent = beforeChild->afterPseudoElementRenderer(); - if (beforeContent && afterContent && isBeforeAfterContentGeneratedByAncestor(this, beforeContent)) { - beforeChildHasBeforeAndAfterContent = true; - beforeContent->destroy(); - } - } - bool needsTable = false; if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP) @@ -320,7 +296,7 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) if (afterChild && afterChild->isAnonymous() && afterChild->isTable() && !afterChild->isBeforeContent()) table = toRenderTable(afterChild); else { - table = createAnonymousTable(); + table = RenderTable::createAnonymousWithParentRenderer(this); addChild(table, beforeChild); } table->addChild(newChild); @@ -329,11 +305,8 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) children->insertChildNode(this, newChild, beforeChild); } - if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) { - RefPtr<StringImpl> textToTransform = toRenderText(newChild)->originalText(); - if (textToTransform) - toRenderText(newChild)->setText(textToTransform.release(), true); - } + if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) + toRenderText(newChild)->transformText(); // SVG creates renderers for <g display="none">, as SVG requires children of hidden // <g>s to have renderers - at least that's how our implementation works. Consider: @@ -345,9 +318,6 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) // and stop creating layers at all for these cases - they're not used anyways. if (newChild->hasLayer() && !layerCreationAllowedForSubtree()) toRenderBoxModelObject(newChild)->layer()->removeOnlyThisLayer(); - - if (beforeChildHasBeforeAndAfterContent) - children->updateBeforeAfterContent(this, BEFORE); } void RenderObject::removeChild(RenderObject* oldChild) @@ -565,6 +535,16 @@ RenderLayer* RenderObject::enclosingLayer() const return 0; } +bool RenderObject::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) +{ + RenderLayer* enclosingLayer = this->enclosingLayer(); + if (!enclosingLayer) + return false; + + enclosingLayer->scrollRectToVisible(rect, alignX, alignY); + return true; +} + RenderBox* RenderObject::enclosingBox() const { RenderObject* curr = const_cast<RenderObject*>(this); @@ -597,7 +577,7 @@ RenderFlowThread* RenderObject::enclosingRenderFlowThread() const return 0; // See if we have the thread cached because we're in the middle of layout. - RenderFlowThread* flowThread = view()->currentRenderFlowThread(); + RenderFlowThread* flowThread = view()->flowThreadController()->currentRenderFlowThread(); if (flowThread) return flowThread; @@ -680,11 +660,11 @@ void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderOb last->scheduleRelayout(); } -void RenderObject::setPreferredLogicalWidthsDirty(bool b, bool markParents) +void RenderObject::setPreferredLogicalWidthsDirty(bool shouldBeDirty, MarkingBehavior markParents) { bool alreadyDirty = preferredLogicalWidthsDirty(); - m_bitfields.setPreferredLogicalWidthsDirty(b); - if (b && !alreadyDirty && markParents && (isText() || !style()->isPositioned())) + m_bitfields.setPreferredLogicalWidthsDirty(shouldBeDirty); + if (shouldBeDirty && !alreadyDirty && markParents == MarkContainingBlockChain && (isText() || !style()->isPositioned())) invalidateContainerPreferredLogicalWidths(); } @@ -1275,11 +1255,19 @@ RenderBoxModelObject* RenderObject::containerForRepaint() const #if USE(ACCELERATED_COMPOSITING) if (v->usesCompositing()) { - RenderLayer* compLayer = enclosingLayer()->enclosingCompositingLayer(); + RenderLayer* compLayer = enclosingLayer()->enclosingCompositingLayerForRepaint(); if (compLayer) repaintContainer = compLayer->renderer(); } #endif + +#if ENABLE(CSS_FILTERS) + if (RenderLayer* parentLayer = enclosingLayer()) { + RenderLayer* enclosingFilterLayer = parentLayer->enclosingFilterLayer(); + if (enclosingFilterLayer) + return enclosingFilterLayer->renderer(); + } +#endif // If we have a flow thread, then we need to do individual repaints within the RenderRegions instead. // Return the flow thread as a repaint container in order to create a chokepoint that allows us to change @@ -1303,12 +1291,19 @@ void RenderObject::repaintUsingContainer(RenderBoxModelObject* repaintContainer, return; } +#if ENABLE(CSS_FILTERS) + if (repaintContainer->hasFilter() && repaintContainer->layer() && repaintContainer->layer()->requiresFullLayerImageForFilters()) { + repaintContainer->layer()->setFilterBackendNeedsRepaintingInRect(r, immediate); + return; + } +#endif + #if USE(ACCELERATED_COMPOSITING) RenderView* v = view(); if (repaintContainer->isRenderView()) { ASSERT(repaintContainer == v); bool viewHasCompositedLayer = v->hasLayer() && v->layer()->isComposited(); - if (!viewHasCompositedLayer || v->layer()->backing()->paintingGoesToWindow()) { + if (!viewHasCompositedLayer || v->layer()->backing()->paintsIntoWindow()) { LayoutRect repaintRectangle = r; if (viewHasCompositedLayer && v->layer()->transform()) repaintRectangle = v->layer()->transform()->mapRect(r); @@ -1362,6 +1357,11 @@ void RenderObject::repaintRectangle(const LayoutRect& r, bool immediate) repaintUsingContainer(repaintContainer ? repaintContainer : view, dirtyRect, immediate); } +IntRect RenderObject::pixelSnappedAbsoluteClippedOverflowRect() const +{ + return pixelSnappedIntRect(absoluteClippedOverflowRect()); +} + bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintContainer, const LayoutRect& oldBounds, const LayoutRect& oldOutlineBox, const LayoutRect* newBoundsPtr, const LayoutRect* newOutlineBoxRectPtr) { RenderView* v = view(); @@ -1429,34 +1429,34 @@ bool RenderObject::repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintConta // two rectangles (but typically only one). RenderStyle* outlineStyle = outlineStyleForRepaint(); LayoutUnit ow = outlineStyle->outlineSize(); - LayoutUnit width = abs(newOutlineBox.width() - oldOutlineBox.width()); + LayoutUnit width = absoluteValue(newOutlineBox.width() - oldOutlineBox.width()); if (width) { LayoutUnit shadowLeft; LayoutUnit shadowRight; style()->getBoxShadowHorizontalExtent(shadowLeft, shadowRight); - LayoutUnit borderRight = isBox() ? toRenderBox(this)->borderRight() : zeroLayoutUnit; - LayoutUnit boxWidth = isBox() ? toRenderBox(this)->width() : zeroLayoutUnit; - LayoutUnit borderWidth = max<LayoutUnit>(-outlineStyle->outlineOffset(), max(borderRight, max<LayoutUnit>(style()->borderTopRightRadius().width().calcValue(boxWidth), style()->borderBottomRightRadius().width().calcValue(boxWidth)))) + max(ow, shadowRight); + int borderRight = isBox() ? toRenderBox(this)->borderRight() : 0; + LayoutUnit boxWidth = isBox() ? toRenderBox(this)->width() : ZERO_LAYOUT_UNIT; + LayoutUnit borderWidth = max<LayoutUnit>(-outlineStyle->outlineOffset(), max<LayoutUnit>(borderRight, max<LayoutUnit>(valueForLength(style()->borderTopRightRadius().width(), boxWidth, v), valueForLength(style()->borderBottomRightRadius().width(), boxWidth, v)))) + max<LayoutUnit>(ow, shadowRight); LayoutRect rightRect(newOutlineBox.x() + min(newOutlineBox.width(), oldOutlineBox.width()) - borderWidth, newOutlineBox.y(), width + borderWidth, max(newOutlineBox.height(), oldOutlineBox.height())); - LayoutUnit right = min(newBounds.maxX(), oldBounds.maxX()); + LayoutUnit right = min<LayoutUnit>(newBounds.maxX(), oldBounds.maxX()); if (rightRect.x() < right) { rightRect.setWidth(min(rightRect.width(), right - rightRect.x())); repaintUsingContainer(repaintContainer, rightRect); } } - LayoutUnit height = abs(newOutlineBox.height() - oldOutlineBox.height()); + LayoutUnit height = absoluteValue(newOutlineBox.height() - oldOutlineBox.height()); if (height) { LayoutUnit shadowTop; LayoutUnit shadowBottom; style()->getBoxShadowVerticalExtent(shadowTop, shadowBottom); - LayoutUnit borderBottom = isBox() ? toRenderBox(this)->borderBottom() : zeroLayoutUnit; - LayoutUnit boxHeight = isBox() ? toRenderBox(this)->height() : zeroLayoutUnit; - LayoutUnit borderHeight = max<LayoutUnit>(-outlineStyle->outlineOffset(), max(borderBottom, max<LayoutUnit>(style()->borderBottomLeftRadius().height().calcValue(boxHeight), style()->borderBottomRightRadius().height().calcValue(boxHeight)))) + max(ow, shadowBottom); + int borderBottom = isBox() ? toRenderBox(this)->borderBottom() : 0; + LayoutUnit boxHeight = isBox() ? toRenderBox(this)->height() : ZERO_LAYOUT_UNIT; + LayoutUnit borderHeight = max<LayoutUnit>(-outlineStyle->outlineOffset(), max<LayoutUnit>(borderBottom, max<LayoutUnit>(valueForLength(style()->borderBottomLeftRadius().height(), boxHeight, v), valueForLength(style()->borderBottomRightRadius().height(), boxHeight, v)))) + max<LayoutUnit>(ow, shadowBottom); LayoutRect bottomRect(newOutlineBox.x(), min(newOutlineBox.maxY(), oldOutlineBox.maxY()) - borderHeight, max(newOutlineBox.width(), oldOutlineBox.width()), @@ -1713,6 +1713,16 @@ StyleDifference RenderObject::adjustStyleDifference(StyleDifference diff, unsign diff = StyleDifferenceRecompositeLayer; } +#if ENABLE(CSS_FILTERS) + if ((contextSensitiveProperties & ContextSensitivePropertyFilter) && hasLayer()) { + RenderLayer* layer = toRenderBoxModelObject(this)->layer(); + if (!layer->isComposited() || layer->paintsWithFilters()) + diff = StyleDifferenceRepaintLayer; + else if (diff < StyleDifferenceRecompositeLayer) + diff = StyleDifferenceRecompositeLayer; + } +#endif + // The answer to requiresLayer() for plugins and iframes can change outside of the style system, // since it depends on whether we decide to composite these elements. When the layer status of // one of these elements changes, we need to force a layout. @@ -1864,7 +1874,10 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS // when scrolling a page with a fixed background image. As an optimization, assuming there are // no fixed positoned elements on the page, we can acclerate scrolling (via blitting) if we // ignore the CSS property "background-attachment: fixed". - shouldBlitOnFixedBackgroundImage = true; +#if PLATFORM(QT) + if (view()->frameView()->delegatesScrolling()) +#endif + shouldBlitOnFixedBackgroundImage = true; #endif bool newStyleSlowScroll = newStyle && !shouldBlitOnFixedBackgroundImage && newStyle->hasFixedBackgroundImage(); @@ -1942,7 +1955,7 @@ void RenderObject::propagateStyleToAnonymousChildren(bool blockChildrenOnly) continue; #endif - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), child->style()->display()); if (style()->specifiesColumns()) { if (child->style()->specifiesColumns()) newStyle->inheritColumnPropertiesFrom(style()); @@ -1955,7 +1968,6 @@ void RenderObject::propagateStyleToAnonymousChildren(bool blockChildrenOnly) if (child->isRelPositioned() && toRenderBlock(child)->isAnonymousBlockContinuation()) newStyle->setPosition(child->style()->position()); - newStyle->setDisplay(child->style()->display()); child->setStyle(newStyle.release()); } } @@ -2011,7 +2023,7 @@ FloatPoint RenderObject::absoluteToLocal(const FloatPoint& containerPoint, bool return transformState.lastPlanarPoint(); } -void RenderObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, bool* wasFixed) const +void RenderObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, ApplyContainerFlipOrNot, bool* wasFixed) const { if (repaintContainer == this) return; @@ -2032,7 +2044,7 @@ void RenderObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b if (o->hasOverflowClip()) transformState.move(-toRenderBox(o)->scrolledContentOffset()); - o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, wasFixed); + o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, DoNotApplyContainerFlip, wasFixed); } void RenderObject::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const @@ -2088,7 +2100,7 @@ FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, RenderB // Track the point at the center of the quad's bounding box. As mapLocalToContainer() calls offsetFromContainer(), // it will use that point as the reference point to decide which column's transform to apply in multiple-column blocks. TransformState transformState(TransformState::ApplyTransformDirection, localQuad.boundingBox().center(), localQuad); - mapLocalToContainer(repaintContainer, fixed, true, transformState, wasFixed); + mapLocalToContainer(repaintContainer, fixed, true, transformState, ApplyContainerFlip, wasFixed); transformState.flatten(); return transformState.lastPlanarQuad(); @@ -2097,7 +2109,7 @@ FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, RenderB FloatPoint RenderObject::localToContainerPoint(const FloatPoint& localPoint, RenderBoxModelObject* repaintContainer, bool fixed, bool* wasFixed) const { TransformState transformState(TransformState::ApplyTransformDirection, localPoint); - mapLocalToContainer(repaintContainer, fixed, true, transformState, wasFixed); + mapLocalToContainer(repaintContainer, fixed, true, transformState, ApplyContainerFlip, wasFixed); transformState.flatten(); return transformState.lastPlanarPoint(); @@ -2177,6 +2189,13 @@ RenderObject* RenderObject::rendererForRootBackground() return this; } +RespectImageOrientationEnum RenderObject::shouldRespectImageOrientation() const +{ + // Respect the image's orientation if it's being used as a full-page image or it's + // an <img> and the setting to respect it everywhere is set. + return document()->isImageDocument() || (document()->settings() && document()->settings()->shouldRespectImageOrientation() && node() && node()->hasTagName(HTMLNames::imgTag)) ? RespectImageOrientation : DoNotRespectImageOrientation; +} + bool RenderObject::hasOutlineAnnotation() const { return node() && node()->isLink() && document()->printing(); @@ -2280,11 +2299,11 @@ void RenderObject::willBeDestroyed() remove(); #ifndef NDEBUG - if (!documentBeingDestroyed() && view() && view()->hasRenderFlowThreads()) { + if (!documentBeingDestroyed() && view() && view()->hasRenderNamedFlowThreads()) { // After remove, the object and the associated information should not be in any flow thread. - const RenderFlowThreadList* flowThreadList = view()->renderFlowThreadList(); - for (RenderFlowThreadList::const_iterator iter = flowThreadList->begin(); iter != flowThreadList->end(); ++iter) { - const RenderFlowThread* renderFlowThread = *iter; + const RenderNamedFlowThreadList* flowThreadList = view()->flowThreadController()->renderNamedFlowThreadList(); + for (RenderNamedFlowThreadList::const_iterator iter = flowThreadList->begin(); iter != flowThreadList->end(); ++iter) { + const RenderNamedFlowThread* renderFlowThread = *iter; ASSERT(!renderFlowThread->hasChild(this)); ASSERT(!renderFlowThread->hasChildInfo(this)); } @@ -2306,6 +2325,8 @@ void RenderObject::willBeDestroyed() toRenderBoxModelObject(this)->destroyLayer(); } + setAncestorLineBoxDirty(false); + clearLayoutRootIfNeeded(); } @@ -2390,6 +2411,11 @@ void RenderObject::updateDragState(bool dragOn) curr->updateDragState(dragOn); } +bool RenderObject::isComposited() const +{ + return hasLayer() && toRenderBoxModelObject(this)->layer()->isComposited(); +} + bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter hitTestFilter) { bool inside = false; @@ -2527,19 +2553,20 @@ PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(PseudoId pseudo, Re parentStyle = style(); } + // FIXME: This "find nearest element parent" should be a helper function. Node* n = node(); while (n && !n->isElementNode()) n = n->parentNode(); if (!n) return 0; + Element* element = toElement(n); - RefPtr<RenderStyle> result; if (pseudo == FIRST_LINE_INHERITED) { - result = document()->styleSelector()->styleForElement(static_cast<Element*>(n), parentStyle, false); + RefPtr<RenderStyle> result = document()->styleResolver()->styleForElement(element, parentStyle, DisallowStyleSharing); result->setStyleType(FIRST_LINE_INHERITED); - } else - result = document()->styleSelector()->pseudoStyleForElement(pseudo, static_cast<Element*>(n), parentStyle); - return result.release(); + return result.release(); + } + return document()->styleResolver()->pseudoStyleForElement(pseudo, element, parentStyle); } static Color decorationColor(RenderObject* renderer) @@ -2663,7 +2690,7 @@ bool RenderObject::willRenderImage(CachedImage*) return !document()->inPageCache() && !document()->view()->isOffscreen(); } -LayoutUnit RenderObject::maximalOutlineSize(PaintPhase p) const +int RenderObject::maximalOutlineSize(PaintPhase p) const { if (p != PaintPhaseOutline && p != PaintPhaseSelfOutline && p != PaintPhaseChildOutlines) return 0; @@ -2701,7 +2728,7 @@ int RenderObject::nextOffset(int current) const void RenderObject::adjustRectForOutlineAndShadow(LayoutRect& rect) const { - LayoutUnit outlineSize = outlineStyleForRepaint()->outlineSize(); + int outlineSize = outlineStyleForRepaint()->outlineSize(); if (const ShadowData* boxShadow = style()->boxShadow()) { boxShadow->adjustRectForShadow(rect, outlineSize); return; @@ -2828,6 +2855,9 @@ CursorDirective RenderObject::getCursor(const LayoutPoint&, Cursor&) const bool RenderObject::canUpdateSelectionOnRootLineBoxes() { + if (needsLayout()) + return false; + RenderBlock* containingBlock = this->containingBlock(); return containingBlock ? !containingBlock->needsLayout() : true; } diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h index 60e2a403c..a4a0596fb 100644 --- a/Source/WebCore/rendering/RenderObject.h +++ b/Source/WebCore/rendering/RenderObject.h @@ -29,16 +29,19 @@ #include "CachedImage.h" #include "Document.h" #include "Element.h" +#include "FractionalLayoutUnit.h" #include "FloatQuad.h" #include "LayoutTypes.h" #include "PaintPhase.h" #include "RenderObjectChildList.h" #include "RenderStyle.h" +#include "ScrollBehavior.h" #include "TextAffinity.h" #include "TransformationMatrix.h" +#include <wtf/HashSet.h> #include <wtf/UnusedParam.h> -#if USE(CG) || USE(CAIRO) || USE(SKIA) || PLATFORM(QT) +#if USE(CG) || USE(CAIRO) || USE(SKIA) || PLATFORM(QT) || PLATFORM(WX) #define HAVE_PATH_BASED_BORDER_RADIUS_DRAWING 1 #endif @@ -96,6 +99,11 @@ enum BoxSide { BSLeft }; +enum MarkingBehavior { + MarkOnlyThis, + MarkContainingBlockChain, +}; + const int caretWidth = 1; #if ENABLE(DASHBOARD_SUPPORT) @@ -116,6 +124,8 @@ struct DashboardRegionValue { }; #endif +typedef WTF::HashSet<const RenderObject*> RenderObjectAncestorLineboxDirtySet; + #ifndef NDEBUG const int showTreeCharacterOffset = 39; #endif @@ -195,6 +205,9 @@ public: void moveLayers(RenderLayer* oldParent, RenderLayer* newParent); RenderLayer* findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint, bool checkParent = true); + // Scrolling is a RenderBox concept, however some code just cares about recursively scrolling our enclosing ScrollableArea(s). + bool scrollRectToVisible(const LayoutRect&, const ScrollAlignment& alignX = ScrollAlignment::alignCenterIfNeeded, const ScrollAlignment& alignY = ScrollAlignment::alignCenterIfNeeded); + // Convenience function for getting to the nearest enclosing box of a RenderObject. RenderBox* enclosingBox() const; RenderBoxModelObject* enclosingBoxModelObject() const; @@ -220,8 +233,6 @@ public: // normal flow object. void handleDynamicFloatPositionChange(); - RenderTable* createAnonymousTable() const; - // RenderObject tree manipulation ////////////////////////////////////////// virtual bool canHaveChildren() const { return virtualChildren(); } @@ -343,6 +354,7 @@ public: #endif virtual bool isRenderFlowThread() const { return false; } + virtual bool isRenderNamedFlowThread() const { return false; } bool canHaveRegionStyle() const { return isRenderBlock() && !isAnonymous() && !isRenderFlowThread(); } bool isRoot() const { return document()->documentElement() == m_node; } @@ -370,6 +382,22 @@ public: bool hasColumns() const { return m_bitfields.hasColumns(); } void setHasColumns(bool b = true) { m_bitfields.setHasColumns(b); } + bool ancestorLineBoxDirty() const { return s_ancestorLineboxDirtySet && s_ancestorLineboxDirtySet->contains(this); } + void setAncestorLineBoxDirty(bool b = true) + { + if (b) { + if (!s_ancestorLineboxDirtySet) + s_ancestorLineboxDirtySet = new RenderObjectAncestorLineboxDirtySet; + s_ancestorLineboxDirtySet->add(this); + } else if (s_ancestorLineboxDirtySet) { + s_ancestorLineboxDirtySet->remove(this); + if (s_ancestorLineboxDirtySet->isEmpty()) { + delete s_ancestorLineboxDirtySet; + s_ancestorLineboxDirtySet = 0; + } + } + } + bool inRenderFlowThread() const { return m_bitfields.inRenderFlowThread(); } void setInRenderFlowThread(bool b = true) { m_bitfields.setInRenderFlowThread(b); } @@ -502,6 +530,7 @@ public: bool hasTransform() const { return m_bitfields.hasTransform(); } bool hasMask() const { return style() && style()->hasMask(); } + bool hasHiddenBackface() const { return style() && style()->backfaceVisibility() == BackfaceVisibilityHidden; } #if ENABLE(CSS_FILTERS) bool hasFilter() const { return style() && style()->hasFilter(); } @@ -556,11 +585,11 @@ public: RenderBoxModelObject* offsetParent() const; void markContainingBlocksForLayout(bool scheduleRelayout = true, RenderObject* newRoot = 0); - void setNeedsLayout(bool b, bool markParents = true); - void setChildNeedsLayout(bool b, bool markParents = true); + void setNeedsLayout(bool needsLayout, MarkingBehavior = MarkContainingBlockChain); + void setChildNeedsLayout(bool childNeedsLayout, MarkingBehavior = MarkContainingBlockChain); void setNeedsPositionedMovementLayout(); void setNeedsSimplifiedNormalFlowLayout(); - void setPreferredLogicalWidthsDirty(bool, bool markParents = true); + void setPreferredLogicalWidthsDirty(bool, MarkingBehavior = MarkContainingBlockChain); void invalidateContainerPreferredLogicalWidths(); void setNeedsLayoutAndPrefWidthsRecalc() @@ -605,6 +634,8 @@ public: void collectDashboardRegions(Vector<DashboardRegionValue>&); #endif + bool isComposited() const; + bool hitTest(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter = HitTestAll); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&); @@ -716,6 +747,7 @@ public: { return clippedOverflowRectForRepaint(0); } + IntRect pixelSnappedAbsoluteClippedOverflowRect() const; virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const; virtual LayoutRect rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, LayoutUnit outlineWidth) const; @@ -744,7 +776,7 @@ public: bool hasReflection() const { return m_bitfields.hasReflection(); } // Applied as a "slop" to dirty rect checks during the outline painting phase's dirty-rect checks. - LayoutUnit maximalOutlineSize(PaintPhase) const; + int maximalOutlineSize(PaintPhase) const; enum SelectionState { SelectionNone, // The object is not selected. @@ -833,7 +865,8 @@ public: // Map points and quads through elements, potentially via 3d transforms. You should never need to call these directly; use // localToAbsolute/absoluteToLocal methods instead. - virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, bool* wasFixed = 0) const; + enum ApplyContainerFlipOrNot { DoNotApplyContainerFlip, ApplyContainerFlip }; + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const; bool shouldUseTransformFromContainer(const RenderObject* container) const; @@ -849,6 +882,8 @@ public: // Return the renderer whose background style is used to paint the root background. Should only be called on the renderer for which isRoot() is true. RenderObject* rendererForRootBackground(); + RespectImageOrientationEnum shouldRespectImageOrientation() const; + protected: inline bool layerCreationAllowedForSubtree() const; @@ -889,6 +924,8 @@ private: RenderObject* m_previous; RenderObject* m_next; + static RenderObjectAncestorLineboxDirtySet* s_ancestorLineboxDirtySet; + #ifndef NDEBUG bool m_hasAXObject : 1; bool m_setNeedsLayoutForbidden : 1; @@ -1031,14 +1068,14 @@ inline bool RenderObject::isBeforeOrAfterContent() const return isBeforeContent() || isAfterContent(); } -inline void RenderObject::setNeedsLayout(bool b, bool markParents) +inline void RenderObject::setNeedsLayout(bool needsLayout, MarkingBehavior markParents) { bool alreadyNeededLayout = m_bitfields.needsLayout(); - m_bitfields.setNeedsLayout(b); - if (b) { + m_bitfields.setNeedsLayout(needsLayout); + if (needsLayout) { ASSERT(!isSetNeedsLayoutForbidden()); if (!alreadyNeededLayout) { - if (markParents) + if (markParents == MarkContainingBlockChain) markContainingBlocksForLayout(); if (hasLayer()) setLayerNeedsFullRepaint(); @@ -1049,16 +1086,17 @@ inline void RenderObject::setNeedsLayout(bool b, bool markParents) setNeedsSimplifiedNormalFlowLayout(false); setNormalChildNeedsLayout(false); setNeedsPositionedMovementLayout(false); + setAncestorLineBoxDirty(false); } } -inline void RenderObject::setChildNeedsLayout(bool b, bool markParents) +inline void RenderObject::setChildNeedsLayout(bool childNeedsLayout, MarkingBehavior markParents) { bool alreadyNeededLayout = normalChildNeedsLayout(); - setNormalChildNeedsLayout(b); - if (b) { + setNormalChildNeedsLayout(childNeedsLayout); + if (childNeedsLayout) { ASSERT(!isSetNeedsLayoutForbidden()); - if (!alreadyNeededLayout && markParents) + if (!alreadyNeededLayout && markParents == MarkContainingBlockChain) markContainingBlocksForLayout(); } else { setPosChildNeedsLayout(false); diff --git a/Source/WebCore/rendering/RenderObjectChildList.cpp b/Source/WebCore/rendering/RenderObjectChildList.cpp index efe6b8520..265596c2b 100644 --- a/Source/WebCore/rendering/RenderObjectChildList.cpp +++ b/Source/WebCore/rendering/RenderObjectChildList.cpp @@ -31,12 +31,12 @@ #include "ContentData.h" #include "RenderBlock.h" #include "RenderCounter.h" -#include "RenderFlowThread.h" #include "RenderImage.h" #include "RenderImageResourceStyleImage.h" #include "RenderInline.h" #include "RenderLayer.h" #include "RenderListItem.h" +#include "RenderNamedFlowThread.h" #include "RenderQuote.h" #include "RenderRegion.h" #include "RenderStyle.h" @@ -63,12 +63,12 @@ void RenderObjectChildList::destroyLeftoverChildren() } } -static RenderFlowThread* renderFlowThreadContainer(RenderObject* object) +static RenderNamedFlowThread* renderNamedFlowThreadContainer(RenderObject* object) { - while (object && object->isAnonymousBlock() && !object->isRenderFlowThread()) + while (object && object->isAnonymousBlock() && !object->isRenderNamedFlowThread()) object = object->parent(); - return object && object->isRenderFlowThread() ? toRenderFlowThread(object) : 0; + return object && object->isRenderNamedFlowThread() ? toRenderNamedFlowThread(object) : 0; } RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove) @@ -120,7 +120,7 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render oldChild->enclosingRenderFlowThread()->clearRenderBoxCustomStyle(toRenderBox(oldChild)); } - if (RenderFlowThread* containerFlowThread = renderFlowThreadContainer(owner)) + if (RenderNamedFlowThread* containerFlowThread = renderNamedFlowThreadContainer(owner)) containerFlowThread->removeFlowChild(oldChild); #if ENABLE(SVG) @@ -203,9 +203,10 @@ void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* n if (newChild->isRenderRegion()) toRenderRegion(newChild)->attachRegion(); - if (RenderFlowThread* containerFlowThread = renderFlowThreadContainer(owner)) + if (RenderNamedFlowThread* containerFlowThread = renderNamedFlowThreadContainer(owner)) containerFlowThread->addFlowChild(newChild); } + RenderCounter::rendererSubtreeAttached(newChild); RenderQuote::rendererSubtreeAttached(newChild); newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy. @@ -269,7 +270,7 @@ void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* c if (child->isRenderRegion()) toRenderRegion(child)->attachRegion(); - if (RenderFlowThread* containerFlowThread = renderFlowThreadContainer(owner)) + if (RenderNamedFlowThread* containerFlowThread = renderNamedFlowThreadContainer(owner)) containerFlowThread->addFlowChild(child, beforeChild); } @@ -345,6 +346,88 @@ RenderObject* RenderObjectChildList::afterPseudoElementRenderer(const RenderObje return last; } +void RenderObjectChildList::updateBeforeAfterStyle(RenderObject* child, PseudoId type, RenderStyle* pseudoElementStyle) +{ + if (!child || child->style()->styleType() != type) + return; + + // We have generated content present still. We want to walk this content and update our + // style information with the new pseudo-element style. + child->setStyle(pseudoElementStyle); + + RenderObject* beforeAfterParent = findBeforeAfterParent(child); + if (!beforeAfterParent) + return; + + // When beforeAfterParent is not equal to child (e.g. in tables), + // we need to create new styles inheriting from pseudoElementStyle + // on all the intermediate parents (leaving their display same). + if (beforeAfterParent != child) { + RenderObject* curr = beforeAfterParent; + while (curr && curr != child) { + ASSERT(curr->isAnonymous()); + RefPtr<RenderStyle> newStyle = RenderStyle::create(); + newStyle->inheritFrom(pseudoElementStyle); + newStyle->setDisplay(curr->style()->display()); + newStyle->setStyleType(curr->style()->styleType()); + curr->setStyle(newStyle); + curr = curr->parent(); + } + } + + // Note that if we ever support additional types of generated content (which should be way off + // in the future), this code will need to be patched. + for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) { + if (genChild->isText()) + // Generated text content is a child whose style also needs to be set to the pseudo-element style. + genChild->setStyle(pseudoElementStyle); + else if (genChild->isImage()) { + // Images get an empty style that inherits from the pseudo. + RefPtr<RenderStyle> style = RenderStyle::create(); + style->inheritFrom(pseudoElementStyle); + genChild->setStyle(style.release()); + } else { + // RenderListItem may insert a list marker here. We do not need to care about this case. + // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it. + ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER); + } + } +} + +static RenderObject* createRenderForBeforeAfterContent(RenderObject* owner, const ContentData* content, RenderStyle* pseudoElementStyle) +{ + RenderObject* renderer = 0; + switch (content->type()) { + case CONTENT_NONE: + break; + case CONTENT_TEXT: + renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, static_cast<const TextContentData*>(content)->text().impl()); + renderer->setStyle(pseudoElementStyle); + break; + case CONTENT_OBJECT: { + RenderImage* image = new (owner->renderArena()) RenderImage(owner->document()); // anonymous object + RefPtr<RenderStyle> style = RenderStyle::create(); + style->inheritFrom(pseudoElementStyle); + image->setStyle(style.release()); + if (const StyleImage* styleImage = static_cast<const ImageContentData*>(content)->image()) + image->setImageResource(RenderImageResourceStyleImage::create(const_cast<StyleImage*>(styleImage))); + else + image->setImageResource(RenderImageResource::create()); + renderer = image; + break; + } + case CONTENT_COUNTER: + renderer = new (owner->renderArena()) RenderCounter(owner->document(), *static_cast<const CounterContentData*>(content)->counter()); + renderer->setStyle(pseudoElementStyle); + break; + case CONTENT_QUOTE: + renderer = new (owner->renderArena()) RenderQuote(owner->document(), static_cast<const QuoteContentData*>(content)->quote()); + renderer->setStyle(pseudoElementStyle); + break; + } + return renderer; +} + void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject) { // Double check that the document did in fact use generated content rules. Otherwise we should not have been called. @@ -390,7 +473,7 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo // If we don't want generated content any longer, or if we have generated content, but it's no longer // identical to the new content data we want to build render objects for, then we nuke all // of the old generated content. - if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) { + if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle, owner->document()) == Node::Detach)) { // Nuke the child. if (child->style()->styleType() == type) { oldContentPresent = false; @@ -414,49 +497,7 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo pseudoElementStyle->setDisplay(INLINE); if (oldContentPresent) { - if (child && child->style()->styleType() == type) { - // We have generated content present still. We want to walk this content and update our - // style information with the new pseudo-element style. - child->setStyle(pseudoElementStyle); - - RenderObject* beforeAfterParent = findBeforeAfterParent(child); - if (!beforeAfterParent) - return; - - // When beforeAfterParent is not equal to child (e.g. in tables), - // we need to create new styles inheriting from pseudoElementStyle - // on all the intermediate parents (leaving their display same). - if (beforeAfterParent != child) { - RenderObject* curr = beforeAfterParent; - while (curr && curr != child) { - ASSERT(curr->isAnonymous()); - RefPtr<RenderStyle> newStyle = RenderStyle::create(); - newStyle->inheritFrom(pseudoElementStyle); - newStyle->setDisplay(curr->style()->display()); - newStyle->setStyleType(curr->style()->styleType()); - curr->setStyle(newStyle); - curr = curr->parent(); - } - } - - // Note that if we ever support additional types of generated content (which should be way off - // in the future), this code will need to be patched. - for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) { - if (genChild->isText()) - // Generated text content is a child whose style also needs to be set to the pseudo-element style. - genChild->setStyle(pseudoElementStyle); - else if (genChild->isImage()) { - // Images get an empty style that inherits from the pseudo. - RefPtr<RenderStyle> style = RenderStyle::create(); - style->inheritFrom(pseudoElementStyle); - genChild->setStyle(style.release()); - } else { - // RenderListItem may insert a list marker here. We do not need to care about this case. - // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it. - ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER); - } - } - } + updateBeforeAfterStyle(child, type, pseudoElementStyle); return; // We've updated the generated content. That's all we needed to do. } @@ -473,38 +514,10 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo // Generated content consists of a single container that houses multiple children (specified // by the content property). This generated content container gets the pseudo-element style set on it. RenderObject* generatedContentContainer = 0; - + // Walk our list of generated content and create render objects for each. for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) { - RenderObject* renderer = 0; - switch (content->type()) { - case CONTENT_NONE: - break; - case CONTENT_TEXT: - renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, static_cast<const TextContentData*>(content)->text().impl()); - renderer->setStyle(pseudoElementStyle); - break; - case CONTENT_OBJECT: { - RenderImage* image = new (owner->renderArena()) RenderImage(owner->document()); // anonymous object - RefPtr<RenderStyle> style = RenderStyle::create(); - style->inheritFrom(pseudoElementStyle); - image->setStyle(style.release()); - if (const StyleImage* styleImage = static_cast<const ImageContentData*>(content)->image()) - image->setImageResource(RenderImageResourceStyleImage::create(const_cast<StyleImage*>(styleImage))); - else - image->setImageResource(RenderImageResource::create()); - renderer = image; - break; - } - case CONTENT_COUNTER: - renderer = new (owner->renderArena()) RenderCounter(owner->document(), *static_cast<const CounterContentData*>(content)->counter()); - renderer->setStyle(pseudoElementStyle); - break; - case CONTENT_QUOTE: - renderer = new (owner->renderArena()) RenderQuote(owner->document(), static_cast<const QuoteContentData*>(content)->quote()); - renderer->setStyle(pseudoElementStyle); - break; - } + RenderObject* renderer = createRenderForBeforeAfterContent(owner, content, pseudoElementStyle); if (renderer) { if (!generatedContentContainer) { diff --git a/Source/WebCore/rendering/RenderObjectChildList.h b/Source/WebCore/rendering/RenderObjectChildList.h index c8fc978e8..cfe902617 100644 --- a/Source/WebCore/rendering/RenderObjectChildList.h +++ b/Source/WebCore/rendering/RenderObjectChildList.h @@ -32,6 +32,7 @@ namespace WebCore { class RenderObject; +class RenderStyle; class RenderObjectChildList { public: @@ -60,6 +61,8 @@ public: RenderObject* afterPseudoElementRenderer(const RenderObject* owner) const; private: + void updateBeforeAfterStyle(RenderObject* child, PseudoId type, RenderStyle* pseudoElementStyle); + RenderObject* m_firstChild; RenderObject* m_lastChild; }; diff --git a/Source/WebCore/rendering/RenderRegion.cpp b/Source/WebCore/rendering/RenderRegion.cpp index 5b7692a6c..a7ba2eadc 100644 --- a/Source/WebCore/rendering/RenderRegion.cpp +++ b/Source/WebCore/rendering/RenderRegion.cpp @@ -30,24 +30,25 @@ #include "config.h" #include "RenderRegion.h" -#include "CSSStyleSelector.h" #include "GraphicsContext.h" #include "HitTestResult.h" #include "IntRect.h" #include "PaintInfo.h" #include "RenderBoxRegionInfo.h" -#include "RenderFlowThread.h" +#include "RenderNamedFlowThread.h" #include "RenderView.h" +#include "StyleResolver.h" namespace WebCore { RenderRegion::RenderRegion(Node* node, RenderFlowThread* flowThread) : RenderReplaced(node, IntSize()) , m_flowThread(flowThread) - , m_parentFlowThread(0) + , m_parentNamedFlowThread(0) , m_isValid(false) , m_hasCustomRegionStyle(false) , m_regionState(RegionUndefined) + , m_dispatchRegionLayoutUpdateEvent(false) { ASSERT(node->document()->cssRegionsEnabled()); } @@ -174,7 +175,7 @@ void RenderRegion::styleDidChange(StyleDifference diff, const RenderStyle* oldSt bool customRegionStyle = false; if (node()) { Element* regionElement = static_cast<Element*>(node()); - customRegionStyle = view()->document()->styleSelector()->checkRegionStyle(regionElement); + customRegionStyle = view()->document()->styleResolver()->checkRegionStyle(regionElement); } setHasCustomRegionStyle(customRegionStyle); } @@ -208,13 +209,13 @@ void RenderRegion::attachRegion() // so we go up the rendering parents and check that this region is not part of the same // flow that it actually needs to display. It would create a circular reference. RenderObject* parentObject = parent(); - m_parentFlowThread = 0; + m_parentNamedFlowThread = 0; for ( ; parentObject; parentObject = parentObject->parent()) { - if (parentObject->isRenderFlowThread()) { - m_parentFlowThread = toRenderFlowThread(parentObject); + if (parentObject->isRenderNamedFlowThread()) { + m_parentNamedFlowThread = toRenderNamedFlowThread(parentObject); // Do not take into account a region that links a flow with itself. The dependency // cannot change, so it is not worth adding it to the list. - if (m_flowThread == m_parentFlowThread) { + if (m_flowThread == m_parentNamedFlowThread) { m_flowThread = 0; return; } @@ -245,7 +246,7 @@ RenderBoxRegionInfo* RenderRegion::setRenderBoxRegionInfo(const RenderBox* box, if (!m_isValid || !m_flowThread) return 0; - OwnPtr<RenderBoxRegionInfo>& boxInfo = m_renderBoxRegionInfo.add(box, nullptr).first->second; + OwnPtr<RenderBoxRegionInfo>& boxInfo = m_renderBoxRegionInfo.add(box, nullptr).iterator->second; if (boxInfo) *boxInfo = RenderBoxRegionInfo(logicalLeftInset, logicalRightInset, containingBlockChainIsInset); else @@ -299,7 +300,7 @@ PassRefPtr<RenderStyle> RenderRegion::computeStyleInRegion(const RenderBox* box) ASSERT(box->node() && box->node()->isElementNode()); Element* element = toElement(box->node()); - RefPtr<RenderStyle> renderBoxRegionStyle = box->view()->document()->styleSelector()->styleForElement(element, 0, false, false, this); + RefPtr<RenderStyle> renderBoxRegionStyle = box->view()->document()->styleResolver()->styleForElement(element, 0, DisallowStyleSharing, MatchAllRules, this); m_renderBoxRegionStyle.add(box, renderBoxRegionStyle); if (!box->hasBoxDecorations()) { diff --git a/Source/WebCore/rendering/RenderRegion.h b/Source/WebCore/rendering/RenderRegion.h index 70fa23b30..1e10bb3ba 100644 --- a/Source/WebCore/rendering/RenderRegion.h +++ b/Source/WebCore/rendering/RenderRegion.h @@ -37,6 +37,7 @@ namespace WebCore { class RenderBox; class RenderBoxRegionInfo; class RenderFlowThread; +class RenderNamedFlowThread; class RenderRegion : public RenderReplaced { public: @@ -56,8 +57,8 @@ public: void attachRegion(); void detachRegion(); + RenderNamedFlowThread* parentNamedFlowThread() const { return m_parentNamedFlowThread; } RenderFlowThread* flowThread() const { return m_flowThread; } - RenderFlowThread* parentFlowThread() const { return m_parentFlowThread; } // Valid regions do not create circular dependencies with other flows. bool isValid() const { return m_isValid; } @@ -92,6 +93,8 @@ public: RegionState regionState() const { return isValid() ? m_regionState : RegionUndefined; } void setRegionState(RegionState regionState) { m_regionState = regionState; } + void setDispatchRegionLayoutUpdateEvent(bool value) { m_dispatchRegionLayoutUpdateEvent = value; } + bool shouldDispatchRegionLayoutUpdateEvent() { return m_dispatchRegionLayoutUpdateEvent; } private: virtual const char* renderName() const { return "RenderRegion"; } @@ -102,10 +105,10 @@ private: RenderFlowThread* m_flowThread; - // If this RenderRegion is displayed as part of another flow, + // If this RenderRegion is displayed as part of another named flow, // we need to create a dependency tree, so that layout of the // regions is always done before the regions themselves. - RenderFlowThread* m_parentFlowThread; + RenderNamedFlowThread* m_parentNamedFlowThread; LayoutRect m_regionRect; // This map holds unique information about a block that is split across regions. @@ -121,6 +124,7 @@ private: bool m_isValid; bool m_hasCustomRegionStyle; RegionState m_regionState; + bool m_dispatchRegionLayoutUpdateEvent; }; inline RenderRegion* toRenderRegion(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderRegionSet.cpp b/Source/WebCore/rendering/RenderRegionSet.cpp new file mode 100644 index 000000000..f9699ac13 --- /dev/null +++ b/Source/WebCore/rendering/RenderRegionSet.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderRegionSet.h" + +namespace WebCore { + +RenderRegionSet::RenderRegionSet(Node* node, RenderFlowThread* flowThread) + : RenderRegion(node, flowThread) +{ +} + +} diff --git a/Source/WebCore/rendering/RenderRegionSet.h b/Source/WebCore/rendering/RenderRegionSet.h new file mode 100644 index 000000000..3977dbc3b --- /dev/null +++ b/Source/WebCore/rendering/RenderRegionSet.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef RenderRegionSet_h +#define RenderRegionSet_h + +#include "RenderRegion.h" +#include "RenderBoxRegionInfo.h" + +namespace WebCore { + +class RenderFlowThread; + +// RenderRegionSet represents a set of regions that all have the same width and height. It is a "composite region box" that +// can be used to represent a single run of contiguous regions. +// +// By combining runs of same-size columns or pages into a single object, we significantly reduce the number of unique RenderObjects +// required to represent those objects. +// +// This class is abstract and is only intended for use by renderers that generate anonymous runs of identical regions, i.e., +// columns and printing. RenderMultiColumnSet and RenderPageSet represent runs of columns and pages respectively. +// +// FIXME: For now we derive from RenderRegion, but this may change at some point. + +class RenderRegionSet : public RenderRegion { +public: + RenderRegionSet(Node*, RenderFlowThread*); + +private: + virtual const char* renderName() const = 0; +}; + +} // namespace WebCore + +#endif // RenderRegionSet_h + diff --git a/Source/WebCore/rendering/RenderReplaced.cpp b/Source/WebCore/rendering/RenderReplaced.cpp index 39bacfa7f..fd6b881b3 100644 --- a/Source/WebCore/rendering/RenderReplaced.cpp +++ b/Source/WebCore/rendering/RenderReplaced.cpp @@ -2,6 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Dirk Mueller (mueller@kde.org) * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) Research In Motion Limited 2011-2012. 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 @@ -43,7 +44,6 @@ const int cDefaultHeight = 150; RenderReplaced::RenderReplaced(Node* node) : RenderBox(node) , m_intrinsicSize(cDefaultWidth, cDefaultHeight) - , m_hasIntrinsicSize(false) { setReplaced(true); } @@ -51,7 +51,6 @@ RenderReplaced::RenderReplaced(Node* node) RenderReplaced::RenderReplaced(Node* node, const IntSize& intrinsicSize) : RenderBox(node) , m_intrinsicSize(intrinsicSize) - , m_hasIntrinsicSize(true) { setReplaced(true); } @@ -146,7 +145,7 @@ void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) else { // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. paintInfo.context->save(); - paintInfo.context->addRoundedRectClip(style()->getRoundedBorderFor(paintRect)); + paintInfo.context->addRoundedRectClip(style()->getRoundedBorderFor(paintRect, view())); } } @@ -162,7 +161,7 @@ void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) if (drawSelectionTint) { LayoutRect selectionPaintingRect = localSelectionRect(); selectionPaintingRect.moveBy(adjustedPaintOffset); - paintInfo.context->fillRect(selectionPaintingRect, selectionBackgroundColor(), style()->colorSpace()); + paintInfo.context->fillRect(pixelSnappedIntRect(selectionPaintingRect), selectionBackgroundColor(), style()->colorSpace()); } } @@ -202,24 +201,6 @@ bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintO return true; } -int RenderReplaced::computeIntrinsicLogicalWidth(RenderBox* contentRenderer, bool includeMaxWidth) const -{ - if (m_hasIntrinsicSize) - return computeReplacedLogicalWidthRespectingMinMaxWidth(calcAspectRatioLogicalWidth(), includeMaxWidth); - ASSERT(contentRenderer); - ASSERT(contentRenderer->style()); - return contentRenderer->computeReplacedLogicalWidthRespectingMinMaxWidth(contentRenderer->computeReplacedLogicalWidthUsing(contentRenderer->style()->logicalWidth()), includeMaxWidth); -} - -int RenderReplaced::computeIntrinsicLogicalHeight(RenderBox* contentRenderer) const -{ - if (m_hasIntrinsicSize) - return computeReplacedLogicalHeightRespectingMinMaxHeight(calcAspectRatioLogicalHeight()); - ASSERT(contentRenderer); - ASSERT(contentRenderer->style()); - return contentRenderer->computeReplacedLogicalHeightRespectingMinMaxHeight(contentRenderer->computeReplacedLogicalHeightUsing(contentRenderer->style()->logicalHeight())); -} - static inline RenderBlock* firstContainingBlockWithLogicalWidth(const RenderReplaced* replaced) { // We have to lookup the containing block, which has an explicit width, which must not be equal to our direct containing block. @@ -282,6 +263,56 @@ bool RenderReplaced::hasReplacedLogicalHeight() const return false; } +static inline bool rendererHasAspectRatio(const RenderObject* renderer) +{ + ASSERT(renderer); + return renderer->isImage() || renderer->isCanvas() || renderer->isVideo(); +} + +void RenderReplaced::computeIntrinsicRatioInformationForRenderBox(RenderBox* contentRenderer, FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const +{ + if (contentRenderer) { + contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); + if (intrinsicRatio) + ASSERT(!isPercentageIntrinsicSize); + + // Handle zoom & vertical writing modes here, as the embedded document doesn't know about them. + if (!isPercentageIntrinsicSize) + intrinsicSize.scale(style()->effectiveZoom()); + + if (intrinsicRatio && !isHorizontalWritingMode()) + intrinsicRatio = 1 / intrinsicRatio; + + if (rendererHasAspectRatio(this) && isPercentageIntrinsicSize) + intrinsicRatio = 1; + return; + } + + // This code path can't yield percentage intrinsic sizes, assert that. + computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); + ASSERT(!isPercentageIntrinsicSize); +} + +void RenderReplaced::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const +{ + // If there's an embeddedContentBox() of a remote, referenced document available, this code-path should never be used. + ASSERT(!embeddedContentBox()); + isPercentageIntrinsicSize = false; + intrinsicSize = FloatSize(intrinsicLogicalWidth(), intrinsicLogicalHeight()); + + // Figure out if we need to compute an intrinsic ratio. + if (intrinsicSize.isEmpty() || !rendererHasAspectRatio(this)) + return; + + intrinsicRatio = intrinsicSize.width() / intrinsicSize.height(); + if (style()->logicalWidth().isAuto() && style()->logicalHeight().isAuto()) { + // We can't multiply or divide by 'intrinsicRatio' here, it breaks tests, like fast/images/zoomed-img-size.html, which + // can only be fixed once subpixel precision is available for things like intrinsicWidth/Height - which include zoom! + intrinsicSize.setWidth(RenderBox::computeReplacedLogicalHeight() * intrinsicLogicalWidth() / intrinsicLogicalHeight()); + intrinsicSize.setHeight(RenderBox::computeReplacedLogicalWidth() * intrinsicLogicalHeight() / intrinsicLogicalWidth()); + } +} + LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) const { if (style()->logicalWidth().isSpecified()) @@ -293,33 +324,25 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) con bool isPercentageIntrinsicSize = false; double intrinsicRatio = 0; FloatSize intrinsicSize; - if (contentRenderer) - contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); - else - computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); - - if (intrinsicRatio && !isHorizontalWritingMode()) - intrinsicRatio = 1 / intrinsicRatio; + computeIntrinsicRatioInformationForRenderBox(contentRenderer, intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); + // FIXME: Remove unnecessary round/roundToInt calls from this method when layout is off ints: webkit.org/b/63656 if (style()->logicalWidth().isAuto()) { bool heightIsAuto = style()->logicalHeight().isAuto(); - bool hasIntrinsicWidth = m_hasIntrinsicSize || (!isPercentageIntrinsicSize && intrinsicSize.width() > 0); + bool hasIntrinsicWidth = !isPercentageIntrinsicSize && intrinsicSize.width() > 0; // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic width, then that intrinsic width is the used value of 'width'. - if (heightIsAuto && hasIntrinsicWidth) { - if (m_hasIntrinsicSize) - return computeReplacedLogicalWidthRespectingMinMaxWidth(calcAspectRatioLogicalWidth(), includeMaxWidth); - return static_cast<LayoutUnit>(intrinsicSize.width() * style()->effectiveZoom()); - } + if (heightIsAuto && hasIntrinsicWidth) + return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(intrinsicSize.width()), includeMaxWidth); - bool hasIntrinsicHeight = m_hasIntrinsicSize || (!isPercentageIntrinsicSize && intrinsicSize.height() > 0); + bool hasIntrinsicHeight = !isPercentageIntrinsicSize && intrinsicSize.height() > 0; if (intrinsicRatio || isPercentageIntrinsicSize) { // If 'height' and 'width' both have computed values of 'auto' and the element has no intrinsic width, but does have an intrinsic height and intrinsic ratio; // or if 'width' has a computed value of 'auto', 'height' has some other computed value, and the element does have an intrinsic ratio; then the used value // of 'width' is: (used height) * (intrinsic ratio) if (intrinsicRatio && ((heightIsAuto && !hasIntrinsicWidth && hasIntrinsicHeight) || !heightIsAuto)) { LayoutUnit logicalHeight = computeReplacedLogicalHeightUsing(style()->logicalHeight()); - return computeReplacedLogicalWidthRespectingMinMaxWidth(static_cast<LayoutUnit>(ceil(logicalHeight * intrinsicRatio))); + return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(round(logicalHeight * intrinsicRatio))); } // If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width, then the used value of @@ -335,26 +358,24 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) con logicalWidth = containingBlock()->availableLogicalWidth(); // This solves above equation for 'width' (== logicalWidth). - LayoutUnit marginStart = style()->marginStart().calcMinValue(logicalWidth); - LayoutUnit marginEnd = style()->marginEnd().calcMinValue(logicalWidth); - logicalWidth = max(0, logicalWidth - (marginStart + marginEnd + (width() - clientWidth()))); + LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), logicalWidth); + LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), logicalWidth); + logicalWidth = max(ZERO_LAYOUT_UNIT, logicalWidth - (marginStart + marginEnd + (width() - clientWidth()))); if (isPercentageIntrinsicSize) - // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 - logicalWidth = static_cast<LayoutUnit>(round(logicalWidth * intrinsicSize.width() / 100)); - return computeReplacedLogicalWidthRespectingMinMaxWidth(logicalWidth); + logicalWidth = roundToInt(logicalWidth * intrinsicSize.width() / 100); + return computeReplacedLogicalWidthRespectingMinMaxWidth(logicalWidth, includeMaxWidth); } } // Otherwise, if 'width' has a computed value of 'auto', and the element has an intrinsic width, then that intrinsic width is the used value of 'width'. - if (hasIntrinsicWidth) { - if (isPercentageIntrinsicSize || m_hasIntrinsicSize) - return computeReplacedLogicalWidthRespectingMinMaxWidth(calcAspectRatioLogicalWidth(), includeMaxWidth); - return static_cast<LayoutUnit>(intrinsicSize.width() * style()->effectiveZoom()); - } + if (hasIntrinsicWidth) + return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(intrinsicSize.width()), includeMaxWidth); // Otherwise, if 'width' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'width' becomes 300px. If 300px is too // wide to fit the device, UAs should use the width of the largest rectangle that has a 2:1 ratio and fits the device instead. - return computeReplacedLogicalWidthRespectingMinMaxWidth(cDefaultWidth, includeMaxWidth); + // Note: We fall through and instead return intrinsicLogicalWidth() here - to preserve existing WebKit behavior, which might or might not be correct, or desired. + // Changing this to return cDefaultWidth, will affect lots of test results. Eg. some tests assume that a blank <img> tag (which implies width/height=auto) + // has no intrinsic size, which is wrong per CSS 2.1, but matches our behavior since a long time. } return computeReplacedLogicalWidthRespectingMinMaxWidth(intrinsicLogicalWidth(), includeMaxWidth); @@ -372,59 +393,28 @@ LayoutUnit RenderReplaced::computeReplacedLogicalHeight() const bool isPercentageIntrinsicSize = false; double intrinsicRatio = 0; FloatSize intrinsicSize; - if (contentRenderer) - contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); - else - computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); - - if (intrinsicRatio && !isHorizontalWritingMode()) - intrinsicRatio = 1 / intrinsicRatio; + computeIntrinsicRatioInformationForRenderBox(contentRenderer, intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); + // FIXME: Remove unnecessary round/roundToInt calls from this method when layout is off ints: webkit.org/b/63656 bool widthIsAuto = style()->logicalWidth().isAuto(); - bool hasIntrinsicHeight = m_hasIntrinsicSize || (!isPercentageIntrinsicSize && intrinsicSize.height() > 0); + bool hasIntrinsicHeight = !isPercentageIntrinsicSize && intrinsicSize.height() > 0; // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic height, then that intrinsic height is the used value of 'height'. - if (widthIsAuto && hasIntrinsicHeight) { - if (m_hasIntrinsicSize) - return computeReplacedLogicalHeightRespectingMinMaxHeight(calcAspectRatioLogicalHeight()); - return static_cast<LayoutUnit>(intrinsicSize.height() * style()->effectiveZoom()); - } + if (widthIsAuto && hasIntrinsicHeight) + return computeReplacedLogicalHeightRespectingMinMaxHeight(roundToInt(intrinsicSize.height())); // Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is: // (used width) / (intrinsic ratio) - if (intrinsicRatio && !isPercentageIntrinsicSize) { - // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 - return computeReplacedLogicalHeightRespectingMinMaxHeight(round(availableLogicalWidth() / intrinsicRatio)); - } + if (intrinsicRatio) + return computeReplacedLogicalHeightRespectingMinMaxHeight(roundToInt(round(availableLogicalWidth() / intrinsicRatio))); // Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic height, then that intrinsic height is the used value of 'height'. - if (hasIntrinsicHeight) { - if (m_hasIntrinsicSize) - return computeReplacedLogicalHeightRespectingMinMaxHeight(calcAspectRatioLogicalHeight()); - return static_cast<LayoutUnit>(intrinsicSize.height() * style()->effectiveZoom()); - } + if (hasIntrinsicHeight) + return computeReplacedLogicalHeightRespectingMinMaxHeight(roundToInt(intrinsicSize.height())); // Otherwise, if 'height' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'height' must be set to the height // of the largest rectangle that has a 2:1 ratio, has a height not greater than 150px, and has a width not greater than the device width. - return computeReplacedLogicalHeightRespectingMinMaxHeight(cDefaultHeight); -} - -int RenderReplaced::calcAspectRatioLogicalWidth() const -{ - int intrinsicWidth = intrinsicLogicalWidth(); - int intrinsicHeight = intrinsicLogicalHeight(); - if (!intrinsicHeight) - return 0; - return RenderBox::computeReplacedLogicalHeight() * intrinsicWidth / intrinsicHeight; -} - -int RenderReplaced::calcAspectRatioLogicalHeight() const -{ - int intrinsicWidth = intrinsicLogicalWidth(); - int intrinsicHeight = intrinsicLogicalHeight(); - if (!intrinsicWidth) - return 0; - return RenderBox::computeReplacedLogicalWidth() * intrinsicHeight / intrinsicWidth; + return computeReplacedLogicalHeightRespectingMinMaxHeight(intrinsicLogicalHeight()); } void RenderReplaced::computePreferredLogicalWidths() @@ -435,7 +425,7 @@ void RenderReplaced::computePreferredLogicalWidths() m_maxPreferredLogicalWidth = computeReplacedLogicalWidth(false) + borderAndPadding; if (style()->maxWidth().isFixed()) - m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : zeroLayoutUnit)); + m_maxPreferredLogicalWidth = min<LayoutUnit>(m_maxPreferredLogicalWidth, style()->maxWidth().value() + (style()->boxSizing() == CONTENT_BOX ? borderAndPadding : ZERO_LAYOUT_UNIT)); if (hasRelativeDimensions()) m_minPreferredLogicalWidth = 0; @@ -488,20 +478,20 @@ LayoutRect RenderReplaced::selectionRectForRepaint(RenderBoxModelObject* repaint return rect; } -IntRect RenderReplaced::localSelectionRect(bool checkWhetherSelected) const +LayoutRect RenderReplaced::localSelectionRect(bool checkWhetherSelected) const { if (checkWhetherSelected && !isSelected()) - return IntRect(); + return LayoutRect(); if (!m_inlineBoxWrapper) // We're a block-level replaced element. Just return our own dimensions. - return IntRect(IntPoint(), size()); + return LayoutRect(LayoutPoint(), size()); RootInlineBox* root = m_inlineBoxWrapper->root(); - int newLogicalTop = root->block()->style()->isFlippedBlocksWritingMode() ? m_inlineBoxWrapper->logicalBottom() - root->selectionBottom() : root->selectionTop() - m_inlineBoxWrapper->logicalTop(); + LayoutUnit newLogicalTop = root->block()->style()->isFlippedBlocksWritingMode() ? m_inlineBoxWrapper->logicalBottom() - root->selectionBottom() : root->selectionTop() - m_inlineBoxWrapper->logicalTop(); if (root->block()->style()->isHorizontalWritingMode()) - return IntRect(0, newLogicalTop, width(), root->selectionHeight()); - return IntRect(newLogicalTop, 0, root->selectionHeight(), height()); + return LayoutRect(0, newLogicalTop, width(), root->selectionHeight()); + return LayoutRect(newLogicalTop, 0, root->selectionHeight(), height()); } void RenderReplaced::setSelectionState(SelectionState state) @@ -537,17 +527,6 @@ bool RenderReplaced::isSelected() const return false; } -IntSize RenderReplaced::intrinsicSize() const -{ - return m_intrinsicSize; -} - -void RenderReplaced::setIntrinsicSize(const IntSize& size) -{ - ASSERT(m_hasIntrinsicSize); - m_intrinsicSize = size; -} - LayoutRect RenderReplaced::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const { if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) diff --git a/Source/WebCore/rendering/RenderReplaced.h b/Source/WebCore/rendering/RenderReplaced.h index 1c6ebbc14..9ebc634b0 100644 --- a/Source/WebCore/rendering/RenderReplaced.h +++ b/Source/WebCore/rendering/RenderReplaced.h @@ -43,7 +43,8 @@ protected: virtual void layout(); - virtual IntSize intrinsicSize() const; + virtual IntSize intrinsicSize() const { return m_intrinsicSize; } + virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const; virtual int minimumReplacedHeight() const { return 0; } @@ -53,28 +54,20 @@ protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - void setIntrinsicSize(const IntSize&); + void setIntrinsicSize(const IntSize& intrinsicSize) { m_intrinsicSize = intrinsicSize; } virtual void intrinsicSizeChanged(); - void setHasIntrinsicSize() { m_hasIntrinsicSize = true; } virtual void paint(PaintInfo&, const LayoutPoint&); bool shouldPaint(PaintInfo&, const LayoutPoint&); - IntRect localSelectionRect(bool checkWhetherSelected = true) const; // This is in local coordinates, but it's a physical rect (so the top left corner is physical top left). + LayoutRect localSelectionRect(bool checkWhetherSelected = true) const; // This is in local coordinates, but it's a physical rect (so the top left corner is physical top left). private: virtual RenderBox* embeddedContentBox() const { return 0; } - int computeIntrinsicLogicalWidth(RenderBox* contentRenderer, bool includeMaxWidth) const; - int computeIntrinsicLogicalHeight(RenderBox* contentRenderer) const; - virtual const char* renderName() const { return "RenderReplaced"; } virtual bool canHaveChildren() const { return false; } virtual void computePreferredLogicalWidths(); - - int calcAspectRatioLogicalWidth() const; - int calcAspectRatioLogicalHeight() const; - virtual void paintReplaced(PaintInfo&, const LayoutPoint&) { } virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const; @@ -84,9 +77,9 @@ private: virtual bool canBeSelectionLeaf() const { return true; } virtual LayoutRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent = true); + void computeIntrinsicRatioInformationForRenderBox(RenderBox*, FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const; IntSize m_intrinsicSize; - bool m_hasIntrinsicSize; }; } diff --git a/Source/WebCore/rendering/RenderRuby.cpp b/Source/WebCore/rendering/RenderRuby.cpp index 41604d6ac..390db2f56 100644 --- a/Source/WebCore/rendering/RenderRuby.cpp +++ b/Source/WebCore/rendering/RenderRuby.cpp @@ -84,9 +84,7 @@ static inline RenderBlock* rubyAfterBlock(const RenderObject* ruby) static RenderBlock* createAnonymousRubyInlineBlock(RenderObject* ruby) { - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(ruby->style()); - newStyle->setDisplay(INLINE_BLOCK); - + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(ruby->style(), INLINE_BLOCK); RenderBlock* newBlock = new (ruby->renderArena()) RenderBlock(ruby->document() /* anonymous box */); newBlock->setStyle(newStyle.release()); return newBlock; diff --git a/Source/WebCore/rendering/RenderRubyBase.cpp b/Source/WebCore/rendering/RenderRubyBase.cpp index d62795538..87402f713 100644 --- a/Source/WebCore/rendering/RenderRubyBase.cpp +++ b/Source/WebCore/rendering/RenderRubyBase.cpp @@ -58,13 +58,9 @@ void RenderRubyBase::moveChildren(RenderRubyBase* toBase, RenderObject* beforeCh // This function removes all children that are before (!) beforeChild // and appends them to toBase. ASSERT_ARG(toBase, toBase); - - // First make sure that beforeChild (if set) is indeed a direct child of this. - // Inline children might be wrapped in an anonymous block if there's a continuation. - // Theoretically, in ruby bases, this can happen with only the first such a child, - // so it should be OK to just climb the tree. - while (beforeChild && beforeChild->parent() != this) - beforeChild = beforeChild->parent(); + + if (beforeChild && beforeChild->parent() != this) + beforeChild = splitAnonymousBoxesAroundChild(beforeChild); if (childrenInline()) moveInlineChildren(toBase, beforeChild); diff --git a/Source/WebCore/rendering/RenderRubyRun.cpp b/Source/WebCore/rendering/RenderRubyRun.cpp index 530c6bdb2..716e55f05 100644 --- a/Source/WebCore/rendering/RenderRubyRun.cpp +++ b/Source/WebCore/rendering/RenderRubyRun.cpp @@ -74,6 +74,9 @@ bool RenderRubyRun::isEmpty() const RenderRubyText* RenderRubyRun::rubyText() const { RenderObject* child = firstChild(); + // If in future it becomes necessary to support floating or positioned ruby text, + // layout will have to be changed to handle them properly. + ASSERT(!child || !child->isRubyText() || !child->isFloatingOrPositioned()); return child && child->isRubyText() ? static_cast<RenderRubyText*>(child) : 0; } @@ -196,8 +199,7 @@ void RenderRubyRun::removeChild(RenderObject* child) RenderRubyBase* RenderRubyRun::createRubyBase() const { RenderRubyBase* rb = new (renderArena()) RenderRubyBase(document() /* anonymous */); - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); - newStyle->setDisplay(BLOCK); + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK); newStyle->setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER? rb->setStyle(newStyle.release()); return rb; @@ -207,8 +209,7 @@ RenderRubyRun* RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby { ASSERT(parentRuby && parentRuby->isRuby()); RenderRubyRun* rr = new (parentRuby->renderArena()) RenderRubyRun(parentRuby->document() /* anonymous */); - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(parentRuby->style()); - newStyle->setDisplay(INLINE_BLOCK); + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parentRuby->style(), INLINE_BLOCK); rr->setStyle(newStyle.release()); return rr; } @@ -220,7 +221,7 @@ RenderObject* RenderRubyRun::layoutSpecialExcludedChild(bool relayoutChildren) if (!rt) return 0; if (relayoutChildren) - rt->setChildNeedsLayout(true, false); + rt->setChildNeedsLayout(true, MarkOnlyThis); rt->layoutIfNeeded(); return rt; } diff --git a/Source/WebCore/rendering/RenderScrollbar.cpp b/Source/WebCore/rendering/RenderScrollbar.cpp index 6f6fd53ea..0c50c0d39 100644 --- a/Source/WebCore/rendering/RenderScrollbar.cpp +++ b/Source/WebCore/rendering/RenderScrollbar.cpp @@ -297,27 +297,26 @@ IntRect RenderScrollbar::buttonRect(ScrollbarPart partType) bool isHorizontal = orientation() == HorizontalScrollbar; if (partType == BackButtonStartPart) - return IntRect(location(), IntSize(isHorizontal ? partRenderer->width() : width(), isHorizontal ? height() : partRenderer->height())); + return IntRect(location(), IntSize(isHorizontal ? partRenderer->pixelSnappedWidth() : width(), isHorizontal ? height() : partRenderer->pixelSnappedHeight())); if (partType == ForwardButtonEndPart) - return IntRect(isHorizontal ? x() + width() - partRenderer->width() : x(), - - isHorizontal ? y() : y() + height() - partRenderer->height(), - isHorizontal ? partRenderer->width() : width(), - isHorizontal ? height() : partRenderer->height()); + return IntRect(isHorizontal ? x() + width() - partRenderer->pixelSnappedWidth() : x(), + isHorizontal ? y() : y() + height() - partRenderer->pixelSnappedHeight(), + isHorizontal ? partRenderer->pixelSnappedWidth() : width(), + isHorizontal ? height() : partRenderer->pixelSnappedHeight()); if (partType == ForwardButtonStartPart) { IntRect previousButton = buttonRect(BackButtonStartPart); return IntRect(isHorizontal ? x() + previousButton.width() : x(), isHorizontal ? y() : y() + previousButton.height(), - isHorizontal ? partRenderer->width() : width(), - isHorizontal ? height() : partRenderer->height()); + isHorizontal ? partRenderer->pixelSnappedWidth() : width(), + isHorizontal ? height() : partRenderer->pixelSnappedHeight()); } IntRect followingButton = buttonRect(ForwardButtonEndPart); - return IntRect(isHorizontal ? x() + width() - followingButton.width() - partRenderer->width() : x(), - isHorizontal ? y() : y() + height() - followingButton.height() - partRenderer->height(), - isHorizontal ? partRenderer->width() : width(), - isHorizontal ? height() : partRenderer->height()); + return IntRect(isHorizontal ? x() + width() - followingButton.width() - partRenderer->pixelSnappedWidth() : x(), + isHorizontal ? y() : y() + height() - followingButton.height() - partRenderer->pixelSnappedHeight(), + isHorizontal ? partRenderer->pixelSnappedWidth() : width(), + isHorizontal ? height() : partRenderer->pixelSnappedHeight()); } IntRect RenderScrollbar::trackRect(int startLength, int endLength) @@ -327,16 +326,16 @@ IntRect RenderScrollbar::trackRect(int startLength, int endLength) part->layout(); if (orientation() == HorizontalScrollbar) { - int marginLeft = part ? part->marginLeft() : 0; - int marginRight = part ? part->marginRight() : 0; + int marginLeft = part ? static_cast<int>(part->marginLeft()) : 0; + int marginRight = part ? static_cast<int>(part->marginRight()) : 0; startLength += marginLeft; endLength += marginRight; int totalLength = startLength + endLength; return IntRect(x() + startLength, y(), width() - totalLength, height()); } - int marginTop = part ? part->marginTop() : 0; - int marginBottom = part ? part->marginBottom() : 0; + int marginTop = part ? static_cast<int>(part->marginTop()) : 0; + int marginBottom = part ? static_cast<int>(part->marginBottom()) : 0; startLength += marginTop; endLength += marginBottom; int totalLength = startLength + endLength; diff --git a/Source/WebCore/rendering/RenderScrollbarPart.cpp b/Source/WebCore/rendering/RenderScrollbarPart.cpp index cbae68c02..1a45be2de 100644 --- a/Source/WebCore/rendering/RenderScrollbarPart.cpp +++ b/Source/WebCore/rendering/RenderScrollbarPart.cpp @@ -79,41 +79,43 @@ void RenderScrollbarPart::layoutVerticalPart() } } -static int calcScrollbarThicknessUsing(const Length& l, int containingLength) +static int calcScrollbarThicknessUsing(const Length& length, int containingLength, RenderView* renderView) { - if (l.isIntrinsicOrAuto()) + if (length.isIntrinsicOrAuto()) return ScrollbarTheme::theme()->scrollbarThickness(); - return l.calcMinValue(containingLength); + return minimumValueForLength(length, containingLength, renderView); } void RenderScrollbarPart::computeScrollbarWidth() { if (!m_scrollbar->owningRenderer()) return; + RenderView* renderView = view(); int visibleSize = m_scrollbar->owningRenderer()->width() - m_scrollbar->owningRenderer()->borderLeft() - m_scrollbar->owningRenderer()->borderRight(); - int w = calcScrollbarThicknessUsing(style()->width(), visibleSize); - int minWidth = calcScrollbarThicknessUsing(style()->minWidth(), visibleSize); - int maxWidth = style()->maxWidth().isUndefined() ? w : calcScrollbarThicknessUsing(style()->maxWidth(), visibleSize); + int w = calcScrollbarThicknessUsing(style()->width(), visibleSize, renderView); + int minWidth = calcScrollbarThicknessUsing(style()->minWidth(), visibleSize, renderView); + int maxWidth = style()->maxWidth().isUndefined() ? w : calcScrollbarThicknessUsing(style()->maxWidth(), visibleSize, renderView); setWidth(max(minWidth, min(maxWidth, w))); // Buttons and track pieces can all have margins along the axis of the scrollbar. - m_marginLeft = style()->marginLeft().calcMinValue(visibleSize); - m_marginRight = style()->marginRight().calcMinValue(visibleSize); + m_marginLeft = minimumValueForLength(style()->marginLeft(), visibleSize, renderView); + m_marginRight = minimumValueForLength(style()->marginRight(), visibleSize, renderView); } void RenderScrollbarPart::computeScrollbarHeight() { if (!m_scrollbar->owningRenderer()) return; + RenderView* renderView = view(); int visibleSize = m_scrollbar->owningRenderer()->height() - m_scrollbar->owningRenderer()->borderTop() - m_scrollbar->owningRenderer()->borderBottom(); - int h = calcScrollbarThicknessUsing(style()->height(), visibleSize); - int minHeight = calcScrollbarThicknessUsing(style()->minHeight(), visibleSize); - int maxHeight = style()->maxHeight().isUndefined() ? h : calcScrollbarThicknessUsing(style()->maxHeight(), visibleSize); + int h = calcScrollbarThicknessUsing(style()->height(), visibleSize, renderView); + int minHeight = calcScrollbarThicknessUsing(style()->minHeight(), visibleSize, renderView); + int maxHeight = style()->maxHeight().isUndefined() ? h : calcScrollbarThicknessUsing(style()->maxHeight(), visibleSize, renderView); setHeight(max(minHeight, min(maxHeight, h))); // Buttons and track pieces can all have margins along the axis of the scrollbar. - m_marginTop = style()->marginTop().calcMinValue(visibleSize); - m_marginBottom = style()->marginBottom().calcMinValue(visibleSize); + m_marginTop = minimumValueForLength(style()->marginTop(), visibleSize, renderView); + m_marginBottom = minimumValueForLength(style()->marginBottom(), visibleSize, renderView); } void RenderScrollbarPart::computePreferredLogicalWidths() @@ -170,7 +172,7 @@ void RenderScrollbarPart::paintIntoRect(GraphicsContext* graphicsContext, const return; // Now do the paint. - PaintInfo paintInfo(graphicsContext, rect, PaintPhaseBlockBackground, false, 0, 0, 0); + PaintInfo paintInfo(graphicsContext, pixelSnappedIntRect(rect), PaintPhaseBlockBackground, false, 0, 0, 0); paint(paintInfo, paintOffset); paintInfo.phase = PaintPhaseChildBlockBackgrounds; paint(paintInfo, paintOffset); diff --git a/Source/WebCore/rendering/RenderScrollbarPart.h b/Source/WebCore/rendering/RenderScrollbarPart.h index e0b9dbe80..fba180e0f 100644 --- a/Source/WebCore/rendering/RenderScrollbarPart.h +++ b/Source/WebCore/rendering/RenderScrollbarPart.h @@ -46,7 +46,13 @@ public: virtual void computePreferredLogicalWidths(); void paintIntoRect(GraphicsContext*, const LayoutPoint&, const LayoutRect&); - + + // Scrollbar parts needs to be rendered at device pixel boundaries. + virtual LayoutUnit marginTop() const { ASSERT(isIntegerValue(m_marginTop)); return m_marginTop; } + virtual LayoutUnit marginBottom() const { ASSERT(isIntegerValue(m_marginBottom)); return m_marginBottom; } + virtual LayoutUnit marginLeft() const { ASSERT(isIntegerValue(m_marginLeft)); return m_marginLeft; } + virtual LayoutUnit marginRight() const { ASSERT(isIntegerValue(m_marginRight)); return m_marginRight; } + protected: virtual void styleWillChange(StyleDifference diff, const RenderStyle* newStyle); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); diff --git a/Source/WebCore/rendering/RenderSelectionInfo.h b/Source/WebCore/rendering/RenderSelectionInfo.h index 6ce05d6be..8936a377e 100644 --- a/Source/WebCore/rendering/RenderSelectionInfo.h +++ b/Source/WebCore/rendering/RenderSelectionInfo.h @@ -62,7 +62,7 @@ class RenderSelectionInfo : public RenderSelectionInfoBase { public: RenderSelectionInfo(RenderObject* o, bool clipToVisibleContent) : RenderSelectionInfoBase(o) - , m_rect(o->needsLayout() ? LayoutRect() : o->selectionRectForRepaint(m_repaintContainer, clipToVisibleContent)) + , m_rect(o->canUpdateSelectionOnRootLineBoxes() ? o->selectionRectForRepaint(m_repaintContainer, clipToVisibleContent) : LayoutRect()) { } @@ -71,10 +71,10 @@ public: m_object->repaintUsingContainer(m_repaintContainer, m_rect); } - IntRect rect() const { return m_rect; } + LayoutRect rect() const { return m_rect; } private: - IntRect m_rect; // relative to repaint container + LayoutRect m_rect; // relative to repaint container }; @@ -83,7 +83,7 @@ class RenderBlockSelectionInfo : public RenderSelectionInfoBase { public: RenderBlockSelectionInfo(RenderBlock* b) : RenderSelectionInfoBase(b) - , m_rects(b->needsLayout() ? GapRects() : block()->selectionGapRectsForRepaint(m_repaintContainer)) + , m_rects(b->canUpdateSelectionOnRootLineBoxes() ? block()->selectionGapRectsForRepaint(m_repaintContainer) : GapRects()) { } diff --git a/Source/WebCore/rendering/RenderSlider.cpp b/Source/WebCore/rendering/RenderSlider.cpp index e1d6ccc52..f78ba5c75 100644 --- a/Source/WebCore/rendering/RenderSlider.cpp +++ b/Source/WebCore/rendering/RenderSlider.cpp @@ -22,7 +22,6 @@ #include "RenderSlider.h" #include "CSSPropertyNames.h" -#include "CSSStyleSelector.h" #include "Document.h" #include "Event.h" #include "EventHandler.h" @@ -40,6 +39,7 @@ #include "ShadowRoot.h" #include "SliderThumbElement.h" #include "StepRange.h" +#include "StyleResolver.h" #include <wtf/MathExtras.h> using std::min; diff --git a/Source/WebCore/rendering/RenderTable.cpp b/Source/WebCore/rendering/RenderTable.cpp index 2c8cae1dd..e7ada7044 100644 --- a/Source/WebCore/rendering/RenderTable.cpp +++ b/Source/WebCore/rendering/RenderTable.cpp @@ -118,7 +118,6 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) if (child->isTableCaption()) { m_captions.append(toRenderTableCaption(child)); - setNeedsSectionRecalc(); wrapInAnonymousSection = false; } else if (child->isTableCol()) { m_hasColElements = true; @@ -159,9 +158,8 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) wrapInAnonymousSection = true; if (!wrapInAnonymousSection) { - // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that. - while (beforeChild && beforeChild->parent() != this) - beforeChild = beforeChild->parent(); + if (beforeChild && beforeChild->parent() != this) + beforeChild = splitAnonymousBoxesAroundChild(beforeChild); RenderBox::addChild(child, beforeChild); return; @@ -192,11 +190,8 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP) beforeChild = 0; - RenderTableSection* section = new (renderArena()) RenderTableSection(document() /* anonymous */); - RefPtr<RenderStyle> newStyle = RenderStyle::create(); - newStyle->inheritFrom(style()); - newStyle->setDisplay(TABLE_ROW_GROUP); - section->setStyle(newStyle.release()); + + RenderTableSection* section = RenderTableSection::createAnonymousWithParentRenderer(this); addChild(section, beforeChild); section->addChild(child); } @@ -222,6 +217,7 @@ void RenderTable::computeLogicalWidth() computePositionedLogicalWidth(); RenderBlock* cb = containingBlock(); + RenderView* renderView = view(); LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent(); bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode(); @@ -232,10 +228,10 @@ void RenderTable::computeLogicalWidth() setLogicalWidth(convertStyleLogicalWidthToComputedWidth(styleLogicalWidth, containerWidthInInlineDirection)); else { // Subtract out any fixed margins from our available width for auto width tables. - LayoutUnit marginStart = style()->marginStart().calcMinValue(availableLogicalWidth); - LayoutUnit marginEnd = style()->marginEnd().calcMinValue(availableLogicalWidth); + LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView); + LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView); LayoutUnit marginTotal = marginStart + marginEnd; - + // Subtract out our margins to get the available content width. LayoutUnit availableContentLogicalWidth = max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal); if (shrinkToAvoidFloats() && cb->containsFloats() && !hasPerpendicularContainingBlock) { @@ -244,25 +240,28 @@ void RenderTable::computeLogicalWidth() } // Ensure we aren't bigger than our available width. - setLogicalWidth(min(availableContentLogicalWidth, maxPreferredLogicalWidth())); + setLogicalWidth(min<int>(availableContentLogicalWidth, maxPreferredLogicalWidth())); } // Ensure we aren't smaller than our min preferred width. - setLogicalWidth(max(logicalWidth(), minPreferredLogicalWidth())); + setLogicalWidth(max<int>(logicalWidth(), minPreferredLogicalWidth())); // Ensure we aren't smaller than our min-width style. Length styleMinLogicalWidth = style()->logicalMinWidth(); if (styleMinLogicalWidth.isSpecified() && styleMinLogicalWidth.isPositive()) - setLogicalWidth(max(logicalWidth(), convertStyleLogicalWidthToComputedWidth(styleMinLogicalWidth, availableLogicalWidth))); + setLogicalWidth(max<int>(logicalWidth(), convertStyleLogicalWidthToComputedWidth(styleMinLogicalWidth, availableLogicalWidth))); // Finally, with our true width determined, compute our margins for real. setMarginStart(0); setMarginEnd(0); - if (!hasPerpendicularContainingBlock) - computeInlineDirectionMargins(cb, availableLogicalWidth, logicalWidth()); - else { - setMarginStart(style()->marginStart().calcMinValue(availableLogicalWidth)); - setMarginEnd(style()->marginEnd().calcMinValue(availableLogicalWidth)); + if (!hasPerpendicularContainingBlock) { + LayoutUnit containerLogicalWidthForAutoMargins = availableLogicalWidth; + if (avoidsFloats() && cb->containsFloats()) + containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(0, 0); // FIXME: Work with regions someday. + computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth()); + } else { + setMarginStart(minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView)); + setMarginEnd(minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView)); } } @@ -270,28 +269,28 @@ void RenderTable::computeLogicalWidth() LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth) { // HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not. - int borders = 0; + LayoutUnit borders = 0; bool isCSSTable = !node() || !node()->hasTagName(tableTag); if (isCSSTable && styleLogicalWidth.isFixed() && styleLogicalWidth.isPositive()) { recalcBordersInRowDirection(); - borders = borderStart() + borderEnd() + (collapseBorders() ? 0 : paddingStart() + paddingEnd()); + borders = borderStart() + borderEnd() + (collapseBorders() ? ZERO_LAYOUT_UNIT : paddingStart() + paddingEnd()); } - return styleLogicalWidth.calcMinValue(availableWidth) + borders; + return minimumValueForLength(styleLogicalWidth, availableWidth, view()) + borders; } void RenderTable::layoutCaption(RenderTableCaption* caption) { - IntRect captionRect(caption->x(), caption->y(), caption->width(), caption->height()); + LayoutRect captionRect(caption->frameRect()); if (caption->needsLayout()) { // The margins may not be available but ensure the caption is at least located beneath any previous sibling caption // so that it does not mistakenly think any floats in the previous caption intrude into it. - caption->setLogicalLocation(IntPoint(caption->marginStart(), caption->marginBefore() + logicalHeight())); + caption->setLogicalLocation(LayoutPoint(caption->marginStart(), caption->marginBefore() + logicalHeight())); // If RenderTableCaption ever gets a layout() function, use it here. caption->layoutIfNeeded(); } // Apply the margins to the location now that they are definitely available from layout - caption->setLogicalLocation(IntPoint(caption->marginStart(), caption->marginBefore() + logicalHeight())); + caption->setLogicalLocation(LayoutPoint(caption->marginStart(), caption->marginBefore() + logicalHeight())); if (!selfNeedsLayout() && caption->checkForRepaintDuringLayout()) caption->repaintDuringLayoutIfMoved(captionRect); @@ -299,6 +298,20 @@ void RenderTable::layoutCaption(RenderTableCaption* caption) setLogicalHeight(logicalHeight() + caption->logicalHeight() + caption->marginBefore() + caption->marginAfter()); } +void RenderTable::distributeExtraLogicalHeight(int extraLogicalHeight) +{ + if (extraLogicalHeight <= 0) + return; + + // FIXME: Distribute the extra logical height between all table sections instead of giving it all to the first one. + if (RenderTableSection* section = firstBody()) + extraLogicalHeight -= section->distributeExtraLogicalHeightToRows(extraLogicalHeight); + + // FIXME: We really would like to enable this ASSERT to ensure that all the extra space has been distributed. + // However our current distribution algorithm does not round properly and thus we can have some remaining height. + // ASSERT(!topSection() || !extraLogicalHeight); +} + void RenderTable::layout() { ASSERT(needsLayout()); @@ -321,7 +334,7 @@ void RenderTable::layout() if (logicalWidth() != oldLogicalWidth) { for (unsigned i = 0; i < m_captions.size(); i++) - m_captions[i]->setNeedsLayout(true, false); + m_captions[i]->setNeedsLayout(true, MarkOnlyThis); } // FIXME: The optimisation below doesn't work since the internal table // layout could have changed. we need to add a flag to the table @@ -372,8 +385,8 @@ void RenderTable::layout() } } - LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? zeroLayoutUnit : paddingBefore()); - LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? zeroLayoutUnit : paddingAfter()); + LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? ZERO_LAYOUT_UNIT : paddingBefore()); + LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? ZERO_LAYOUT_UNIT : paddingAfter()); setLogicalHeight(logicalHeight() + borderAndPaddingBefore); @@ -384,17 +397,16 @@ void RenderTable::layout() LayoutUnit computedLogicalHeight = 0; if (logicalHeightLength.isFixed()) { // HTML tables size as though CSS height includes border/padding, CSS tables do not. - LayoutUnit borders = node() && node()->hasTagName(tableTag) ? (borderAndPaddingBefore + borderAndPaddingAfter) : zeroLayoutUnit; + LayoutUnit borders = node() && node()->hasTagName(tableTag) ? (borderAndPaddingBefore + borderAndPaddingAfter) : ZERO_LAYOUT_UNIT; computedLogicalHeight = logicalHeightLength.value() - borders; } else if (logicalHeightLength.isPercent()) computedLogicalHeight = computePercentageLogicalHeight(logicalHeightLength); computedLogicalHeight = max<LayoutUnit>(0, computedLogicalHeight); - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->isTableSection()) - // FIXME: Distribute the extra logical height between all table sections instead of giving it all to the first one. - toRenderTableSection(child)->layoutRows(child == topSection() ? max<LayoutUnit>(0, computedLogicalHeight - totalSectionLogicalHeight) : 0); - } + distributeExtraLogicalHeight(floorToInt(computedLogicalHeight - totalSectionLogicalHeight)); + + for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) + section->layoutRows(); if (!topSection() && computedLogicalHeight > totalSectionLogicalHeight && !document()->inQuirksMode()) { // Completely empty tables (with no sections or anything) should at least honor specified height @@ -494,7 +506,7 @@ void RenderTable::addOverflowFromChildren() int bottomBorderOverflow = height() + outerBorderBottom() - borderBottom(); int topBorderOverflow = borderTop() - outerBorderTop(); IntRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow); - if (borderOverflowRect != borderBoxRect()) { + if (borderOverflowRect != pixelSnappedBorderBoxRect()) { addLayoutOverflow(borderOverflowRect); addVisualOverflow(borderOverflowRect); } @@ -778,46 +790,51 @@ void RenderTable::recalcSections() const m_foot = 0; m_firstBody = 0; m_hasColElements = false; + m_captions.clear(); // We need to get valid pointers to caption, head, foot and first body again RenderObject* nextSibling; for (RenderObject* child = firstChild(); child; child = nextSibling) { nextSibling = child->nextSibling(); switch (child->style()->display()) { - case TABLE_COLUMN: - case TABLE_COLUMN_GROUP: - m_hasColElements = true; - break; - case TABLE_HEADER_GROUP: - if (child->isTableSection()) { - RenderTableSection* section = toRenderTableSection(child); - if (!m_head) - m_head = section; - else if (!m_firstBody) - m_firstBody = section; - section->recalcCellsIfNeeded(); - } - break; - case TABLE_FOOTER_GROUP: - if (child->isTableSection()) { - RenderTableSection* section = toRenderTableSection(child); - if (!m_foot) - m_foot = section; - else if (!m_firstBody) - m_firstBody = section; - section->recalcCellsIfNeeded(); - } - break; - case TABLE_ROW_GROUP: - if (child->isTableSection()) { - RenderTableSection* section = toRenderTableSection(child); - if (!m_firstBody) - m_firstBody = section; - section->recalcCellsIfNeeded(); - } - break; - default: - break; + case TABLE_CAPTION: + if (child->isTableCaption()) + m_captions.append(toRenderTableCaption(child)); + break; + case TABLE_COLUMN: + case TABLE_COLUMN_GROUP: + m_hasColElements = true; + break; + case TABLE_HEADER_GROUP: + if (child->isTableSection()) { + RenderTableSection* section = toRenderTableSection(child); + if (!m_head) + m_head = section; + else if (!m_firstBody) + m_firstBody = section; + section->recalcCellsIfNeeded(); + } + break; + case TABLE_FOOTER_GROUP: + if (child->isTableSection()) { + RenderTableSection* section = toRenderTableSection(child); + if (!m_foot) + m_foot = section; + else if (!m_firstBody) + m_firstBody = section; + section->recalcCellsIfNeeded(); + } + break; + case TABLE_ROW_GROUP: + if (child->isTableSection()) { + RenderTableSection* section = toRenderTableSection(child); + if (!m_firstBody) + m_firstBody = section; + section->recalcCellsIfNeeded(); + } + break; + default: + break; } } @@ -1114,7 +1131,7 @@ RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const recalcSectionsIfNeeded(); // Find the section and row to look in - unsigned r = cell->row(); + unsigned r = cell->rowIndex(); RenderTableSection* section = 0; unsigned rAbove = 0; if (r > 0) { @@ -1143,7 +1160,7 @@ RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const recalcSectionsIfNeeded(); // Find the section and row to look in - unsigned r = cell->row() + cell->rowSpan() - 1; + unsigned r = cell->rowIndex() + cell->rowSpan() - 1; RenderTableSection* section = 0; unsigned rBelow = 0; if (r < cell->section()->numRows() - 1) { @@ -1175,7 +1192,7 @@ RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const return 0; // If we hit a colspan back up to a real cell. - RenderTableSection::CellStruct& prevCell = section->cellAt(cell->row(), effCol - 1); + RenderTableSection::CellStruct& prevCell = section->cellAt(cell->rowIndex(), effCol - 1); return prevCell.primaryCell(); } @@ -1186,7 +1203,7 @@ RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const unsigned effCol = colToEffCol(cell->col() + cell->colSpan()); if (effCol >= numEffCols()) return 0; - return cell->section()->primaryCellAt(cell->row(), effCol); + return cell->section()->primaryCellAt(cell->rowIndex(), effCol); } RenderBlock* RenderTable::firstLineBlock() const @@ -1263,4 +1280,12 @@ bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu return false; } +RenderTable* RenderTable::createAnonymousWithParentRenderer(const RenderObject* parent) +{ + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE); + RenderTable* newTable = new (parent->renderArena()) RenderTable(parent->document() /* is anonymous */); + newTable->setStyle(newStyle.release()); + return newTable; +} + } diff --git a/Source/WebCore/rendering/RenderTable.h b/Source/WebCore/rendering/RenderTable.h index d4e4fca91..b61c95dc1 100644 --- a/Source/WebCore/rendering/RenderTable.h +++ b/Source/WebCore/rendering/RenderTable.h @@ -45,7 +45,7 @@ public: explicit RenderTable(Node*); virtual ~RenderTable(); - LayoutUnit getColumnPos(unsigned col) const { return m_columnPos[col]; } + int getColumnPos(unsigned col) const { return m_columnPos[col]; } int hBorderSpacing() const { return m_hSpacing; } int vBorderSpacing() const { return m_vSpacing; } @@ -136,7 +136,7 @@ public: }; Vector<ColumnStruct>& columns() { return m_columns; } - Vector<LayoutUnit>& columnPositions() { return m_columnPos; } + Vector<int>& columnPositions() { return m_columnPos; } RenderTableSection* header() const { return m_head; } RenderTableSection* footer() const { return m_foot; } RenderTableSection* firstBody() const { return m_firstBody; } @@ -172,7 +172,7 @@ public: LayoutUnit bordersPaddingAndSpacingInRowDirection() const { return borderStart() + borderEnd() + - (collapseBorders() ? zeroLayoutUnit : (paddingStart() + paddingEnd() + (numEffCols() + 1) * hBorderSpacing())); + (collapseBorders() ? ZERO_LAYOUT_UNIT : (paddingStart() + paddingEnd() + static_cast<LayoutUnit>(numEffCols() + 1) * hBorderSpacing())); } RenderTableCol* colElement(unsigned col, bool* startEdge = 0, bool* endEdge = 0) const; @@ -211,6 +211,12 @@ public: recalcSections(); } + static RenderTable* createAnonymousWithParentRenderer(const RenderObject*); + virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const OVERRIDE + { + return createAnonymousWithParentRenderer(parent); + } + protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); @@ -252,7 +258,9 @@ private: void recalcSections() const; void layoutCaption(RenderTableCaption*); - mutable Vector<LayoutUnit> m_columnPos; + void distributeExtraLogicalHeight(int extraLogicalHeight); + + mutable Vector<int> m_columnPos; mutable Vector<ColumnStruct> m_columns; mutable Vector<RenderTableCaption*> m_captions; diff --git a/Source/WebCore/rendering/RenderTableCell.cpp b/Source/WebCore/rendering/RenderTableCell.cpp index 4243848d9..ec33a7c9f 100644 --- a/Source/WebCore/rendering/RenderTableCell.cpp +++ b/Source/WebCore/rendering/RenderTableCell.cpp @@ -43,9 +43,8 @@ using namespace HTMLNames; RenderTableCell::RenderTableCell(Node* node) : RenderBlock(node) - , m_row(unsetRowIndex) - , m_cellWidthChanged(false) , m_column(unsetColumnIndex) + , m_cellWidthChanged(false) , m_hasAssociatedTableCellElement(node && (node->hasTagName(tdTag) || node->hasTagName(thTag))) , m_intrinsicPaddingBefore(0) , m_intrinsicPaddingAfter(0) @@ -95,7 +94,7 @@ LayoutUnit RenderTableCell::logicalHeightForRowSizing() const { LayoutUnit adjustedLogicalHeight = logicalHeight() - (intrinsicPaddingBefore() + intrinsicPaddingAfter()); - LayoutUnit styleLogicalHeight = style()->logicalHeight().calcValue(0); + LayoutUnit styleLogicalHeight = valueForLength(style()->logicalHeight(), 0, view()); if (document()->inQuirksMode() || style()->boxSizing() == BORDER_BOX) { // Explicit heights use the border box in quirks mode. // Don't adjust height. @@ -143,7 +142,7 @@ Length RenderTableCell::styleOrColLogicalWidth() const // Percentages don't need to be handled since they're always treated this way (even when specified on the cells). // See Bugzilla bug 8126 for details. if (colWidthSum.isFixed() && colWidthSum.value() > 0) - colWidthSum = Length(max<LayoutUnit>(0, colWidthSum.value() - borderAndPaddingLogicalWidth()), Fixed); + colWidthSum = Length(max(0.0f, colWidthSum.value() - borderAndPaddingLogicalWidth()), Fixed); return colWidthSum; } @@ -191,53 +190,47 @@ void RenderTableCell::layout() setCellWidthChanged(false); } -LayoutUnit RenderTableCell::paddingTop(PaddingOptions paddingOption) const +LayoutUnit RenderTableCell::paddingTop() const { - LayoutUnit result = RenderBlock::paddingTop(); - if (paddingOption == ExcludeIntrinsicPadding || !isHorizontalWritingMode()) + LayoutUnit result = computedCSSPaddingTop(); + if (!isHorizontalWritingMode()) return result; return result + (style()->writingMode() == TopToBottomWritingMode ? intrinsicPaddingBefore() : intrinsicPaddingAfter()); } -LayoutUnit RenderTableCell::paddingBottom(PaddingOptions paddingOption) const +LayoutUnit RenderTableCell::paddingBottom() const { - LayoutUnit result = RenderBlock::paddingBottom(); - if (paddingOption == ExcludeIntrinsicPadding || !isHorizontalWritingMode()) + LayoutUnit result = computedCSSPaddingBottom(); + if (!isHorizontalWritingMode()) return result; return result + (style()->writingMode() == TopToBottomWritingMode ? intrinsicPaddingAfter() : intrinsicPaddingBefore()); } -LayoutUnit RenderTableCell::paddingLeft(PaddingOptions paddingOption) const +LayoutUnit RenderTableCell::paddingLeft() const { - LayoutUnit result = RenderBlock::paddingLeft(); - if (paddingOption == ExcludeIntrinsicPadding || isHorizontalWritingMode()) + LayoutUnit result = computedCSSPaddingLeft(); + if (isHorizontalWritingMode()) return result; return result + (style()->writingMode() == LeftToRightWritingMode ? intrinsicPaddingBefore() : intrinsicPaddingAfter()); } -LayoutUnit RenderTableCell::paddingRight(PaddingOptions paddingOption) const +LayoutUnit RenderTableCell::paddingRight() const { - LayoutUnit result = RenderBlock::paddingRight(); - if (paddingOption == ExcludeIntrinsicPadding || isHorizontalWritingMode()) + LayoutUnit result = computedCSSPaddingRight(); + if (isHorizontalWritingMode()) return result; return result + (style()->writingMode() == LeftToRightWritingMode ? intrinsicPaddingAfter() : intrinsicPaddingBefore()); } -LayoutUnit RenderTableCell::paddingBefore(PaddingOptions paddingOption) const +LayoutUnit RenderTableCell::paddingBefore() const { - LayoutUnit result = RenderBlock::paddingBefore(); - if (paddingOption == ExcludeIntrinsicPadding) - return result; - return result + intrinsicPaddingBefore(); + return computedCSSPaddingBefore() + intrinsicPaddingBefore(); } -LayoutUnit RenderTableCell::paddingAfter(PaddingOptions paddingOption) const +LayoutUnit RenderTableCell::paddingAfter() const { - LayoutUnit result = RenderBlock::paddingAfter(); - if (paddingOption == ExcludeIntrinsicPadding) - return result; - return result + intrinsicPaddingAfter(); + return computedCSSPaddingAfter() + intrinsicPaddingAfter(); } void RenderTableCell::setOverrideHeightFromRowHeight(LayoutUnit rowHeight) @@ -296,9 +289,8 @@ LayoutRect RenderTableCell::clippedOverflowRectForRepaint(RenderBoxModelObject* right = max(right, below->borderHalfRight(true)); } } - left = max(left, -minXVisualOverflow()); - top = max(top, -minYVisualOverflow()); - LayoutRect r(-left, - top, left + max(width() + right, maxXVisualOverflow()), top + max(height() + bottom, maxYVisualOverflow())); + LayoutPoint location(max<LayoutUnit>(left, -minXVisualOverflow()), max<LayoutUnit>(top, -minYVisualOverflow())); + LayoutRect r(-location.x(), -location.y(), location.x() + max(width() + right, maxXVisualOverflow()), location.y() + max(height() + bottom, maxYVisualOverflow())); if (RenderView* v = view()) { // FIXME: layoutDelta needs to be applied in parts before/after transforms and @@ -328,18 +320,19 @@ LayoutUnit RenderTableCell::cellBaselinePosition() const LayoutUnit firstLineBaseline = firstLineBoxBaseline(); if (firstLineBaseline != -1) return firstLineBaseline; - return paddingBefore() + borderBefore() + contentLogicalHeight(IncludeIntrinsicPadding); + return paddingBefore() + borderBefore() + contentLogicalHeight(); } void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { ASSERT(style()->display() == TABLE_CELL); + ASSERT(!row() || row()->rowIndexWasSet()); RenderBlock::styleDidChange(diff, oldStyle); setHasBoxDecorations(true); - if (parent() && section() && oldStyle && style()->height() != oldStyle->height() && rowWasSet()) - section()->rowLogicalHeightChanged(row()); + if (parent() && section() && oldStyle && style()->height() != oldStyle->height()) + section()->rowLogicalHeightChanged(rowIndex()); // If border was changed, notify table. if (parent()) { @@ -604,7 +597,7 @@ CollapsedBorderValue RenderTableCell::computeCollapsedBeforeBorder(IncludeBorder // Now check row groups. RenderTableSection* currSection = section(); - if (!row()) { + if (!rowIndex()) { // (5) Our row group's before border. result = chooseBorder(result, CollapsedBorderValue(currSection->style()->borderBefore(), includeColor ? currSection->style()->visitedDependentColor(beforeColorProperty) : Color(), BROWGROUP)); if (!result.exists()) @@ -682,7 +675,7 @@ CollapsedBorderValue RenderTableCell::computeCollapsedAfterBorder(IncludeBorderC // Now check row groups. RenderTableSection* currSection = section(); - if (row() + rowSpan() >= currSection->numRows()) { + if (rowIndex() + rowSpan() >= currSection->numRows()) { // (5) Our row group's after border. result = chooseBorder(result, CollapsedBorderValue(currSection->style()->borderAfter(), includeColor ? currSection->style()->visitedDependentColor(afterColorProperty) : Color(), BROWGROUP)); if (!result.exists()) @@ -1118,4 +1111,12 @@ void RenderTableCell::scrollbarsChanged(bool horizontalScrollbarChanged, bool ve setIntrinsicPaddingAfter(intrinsicPaddingAfter() - scrollbarHeight); } +RenderTableCell* RenderTableCell::createAnonymousWithParentRenderer(const RenderObject* parent) +{ + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE_CELL); + RenderTableCell* newCell = new (parent->renderArena()) RenderTableCell(parent->document() /* is anonymous */); + newCell->setStyle(newStyle.release()); + return newCell; +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderTableCell.h b/Source/WebCore/rendering/RenderTableCell.h index e18372ac5..dac8a7606 100644 --- a/Source/WebCore/rendering/RenderTableCell.h +++ b/Source/WebCore/rendering/RenderTableCell.h @@ -25,15 +25,13 @@ #ifndef RenderTableCell_h #define RenderTableCell_h +#include "RenderTableRow.h" #include "RenderTableSection.h" namespace WebCore { -static const unsigned unsetColumnIndex = 0x7FFFFFFF; -static const unsigned maxColumnIndex = 0x7FFFFFFE; // 2,147,483,646 - -static const unsigned unsetRowIndex = 0x7FFFFFFF; -static const unsigned maxRowIndex = 0x7FFFFFFE; // 2,147,483,646 +static const unsigned unsetColumnIndex = 0x3FFFFFFF; +static const unsigned maxColumnIndex = 0x3FFFFFFE; // 1,073,741,823 enum IncludeBorderColorOrNot { DoNotIncludeBorderColor, IncludeBorderColor }; @@ -65,24 +63,17 @@ public: return m_column; } - void setRow(unsigned row) - { - if (UNLIKELY(row > maxRowIndex)) - CRASH(); - - m_row = row; - } + RenderTableRow* row() const { return toRenderTableRow(parent()); } + RenderTableSection* section() const { return toRenderTableSection(parent()->parent()); } + RenderTable* table() const { return toRenderTable(parent()->parent()->parent()); } - bool rowWasSet() const { return m_row != unsetRowIndex; } - unsigned row() const + unsigned rowIndex() const { - ASSERT(rowWasSet()); - return m_row; + // This function shouldn't be called on a detached cell. + ASSERT(row()); + return row()->rowIndex(); } - RenderTableSection* section() const { return toRenderTableSection(parent()->parent()); } - RenderTable* table() const { return toRenderTable(parent()->parent()->parent()); } - Length styleOrColLogicalWidth() const; LayoutUnit logicalHeightForRowSizing() const; @@ -120,16 +111,16 @@ public: int intrinsicPaddingBefore() const { return m_intrinsicPaddingBefore; } int intrinsicPaddingAfter() const { return m_intrinsicPaddingAfter; } - virtual LayoutUnit paddingTop(PaddingOptions = IncludeIntrinsicPadding) const; - virtual LayoutUnit paddingBottom(PaddingOptions = IncludeIntrinsicPadding) const; - virtual LayoutUnit paddingLeft(PaddingOptions = IncludeIntrinsicPadding) const; - virtual LayoutUnit paddingRight(PaddingOptions = IncludeIntrinsicPadding) const; + virtual LayoutUnit paddingTop() const OVERRIDE; + virtual LayoutUnit paddingBottom() const OVERRIDE; + virtual LayoutUnit paddingLeft() const OVERRIDE; + virtual LayoutUnit paddingRight() const OVERRIDE; // FIXME: For now we just assume the cell has the same block flow direction as the table. It's likely we'll // create an extra anonymous RenderBlock to handle mixing directionality anyway, in which case we can lock // the block flow directionality of the cells to the table's directionality. - virtual LayoutUnit paddingBefore(PaddingOptions = IncludeIntrinsicPadding) const; - virtual LayoutUnit paddingAfter(PaddingOptions = IncludeIntrinsicPadding) const; + virtual LayoutUnit paddingBefore() const OVERRIDE; + virtual LayoutUnit paddingAfter() const OVERRIDE; void setOverrideHeightFromRowHeight(LayoutUnit); @@ -138,6 +129,12 @@ public: bool cellWidthChanged() const { return m_cellWidthChanged; } void setCellWidthChanged(bool b = true) { m_cellWidthChanged = b; } + static RenderTableCell* createAnonymousWithParentRenderer(const RenderObject*); + virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const OVERRIDE + { + return createAnonymousWithParentRenderer(parent); + } + protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); @@ -184,9 +181,8 @@ private: CollapsedBorderValue computeCollapsedBeforeBorder(IncludeBorderColorOrNot = IncludeBorderColor) const; CollapsedBorderValue computeCollapsedAfterBorder(IncludeBorderColorOrNot = IncludeBorderColor) const; - unsigned m_row : 31; + unsigned m_column : 30; bool m_cellWidthChanged : 1; - unsigned m_column : 31; bool m_hasAssociatedTableCellElement : 1; int m_intrinsicPaddingBefore; int m_intrinsicPaddingAfter; diff --git a/Source/WebCore/rendering/RenderTableCol.h b/Source/WebCore/rendering/RenderTableCol.h index 76c28a3a5..da037b863 100644 --- a/Source/WebCore/rendering/RenderTableCol.h +++ b/Source/WebCore/rendering/RenderTableCol.h @@ -43,7 +43,7 @@ public: unsigned span() const { return m_span; } void setSpan(unsigned span) { m_span = span; } - + bool isTableColGroup() { return firstChild() ? true : false; } private: virtual RenderObjectChildList* virtualChildren() { return children(); } virtual const RenderObjectChildList* virtualChildren() const { return children(); } diff --git a/Source/WebCore/rendering/RenderTableRow.cpp b/Source/WebCore/rendering/RenderTableRow.cpp index 23227448e..d9889008b 100644 --- a/Source/WebCore/rendering/RenderTableRow.cpp +++ b/Source/WebCore/rendering/RenderTableRow.cpp @@ -38,6 +38,7 @@ using namespace HTMLNames; RenderTableRow::RenderTableRow(Node* node) : RenderBox(node) + , m_rowIndex(unsetRowIndex) { // init RenderObject attributes setInline(false); // our object is not Inline @@ -72,7 +73,7 @@ void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* old updateBeforeAndAfterContent(); if (section() && oldStyle && style()->logicalHeight() != oldStyle->logicalHeight()) - section()->rowLogicalHeightChanged(section()->rowIndexForRenderer(this)); + section()->rowLogicalHeightChanged(rowIndex()); // If border was changed, notify table. if (parent()) { @@ -113,19 +114,14 @@ void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) return; } - RenderTableCell* cell = new (renderArena()) RenderTableCell(document() /* anonymous object */); - RefPtr<RenderStyle> newStyle = RenderStyle::create(); - newStyle->inheritFrom(style()); - newStyle->setDisplay(TABLE_CELL); - cell->setStyle(newStyle.release()); + RenderTableCell* cell = RenderTableCell::createAnonymousWithParentRenderer(this); addChild(cell, beforeChild); cell->addChild(child); return; } - - // If the next renderer is actually wrapped in an anonymous table cell, we need to go up and find that. - while (beforeChild && beforeChild->parent() != this) - beforeChild = beforeChild->parent(); + + if (beforeChild && beforeChild->parent() != this) + beforeChild = splitAnonymousBoxesAroundChild(beforeChild); RenderTableCell* cell = toRenderTableCell(child); @@ -153,7 +149,7 @@ void RenderTableRow::layout() if (child->isTableCell()) { RenderTableCell* cell = toRenderTableCell(child); if (!cell->needsLayout() && paginated && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell->logicalTop()) != cell->pageLogicalOffset()) - cell->setChildNeedsLayout(true, false); + cell->setChildNeedsLayout(true, MarkOnlyThis); if (child->needsLayout()) { cell->computeBlockDirectionMargins(table()); @@ -249,4 +245,12 @@ void RenderTableRow::imageChanged(WrappedImagePtr, const IntRect*) repaint(); } +RenderTableRow* RenderTableRow::createAnonymousWithParentRenderer(const RenderObject* parent) +{ + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE_ROW); + RenderTableRow* newRow = new (parent->renderArena()) RenderTableRow(parent->document() /* is anonymous */); + newRow->setStyle(newStyle.release()); + return newRow; +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderTableRow.h b/Source/WebCore/rendering/RenderTableRow.h index f3175dfc0..04696607d 100644 --- a/Source/WebCore/rendering/RenderTableRow.h +++ b/Source/WebCore/rendering/RenderTableRow.h @@ -29,6 +29,9 @@ namespace WebCore { +static const unsigned unsetRowIndex = 0x7FFFFFFF; +static const unsigned maxRowIndex = 0x7FFFFFFE; // 2,147,483,646 + class RenderTableRow : public RenderBox { public: explicit RenderTableRow(Node*); @@ -42,6 +45,27 @@ public: void updateBeforeAndAfterContent(); void paintOutlineForRowIfNeeded(PaintInfo&, const LayoutPoint&); + static RenderTableRow* createAnonymousWithParentRenderer(const RenderObject*); + virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const OVERRIDE + { + return createAnonymousWithParentRenderer(parent); + } + + void setRowIndex(unsigned rowIndex) + { + if (UNLIKELY(rowIndex > maxRowIndex)) + CRASH(); + + m_rowIndex = rowIndex; + } + + bool rowIndexWasSet() const { return m_rowIndex != unsetRowIndex; } + unsigned rowIndex() const + { + ASSERT(rowIndexWasSet()); + return m_rowIndex; + } + private: virtual RenderObjectChildList* virtualChildren() { return children(); } virtual const RenderObjectChildList* virtualChildren() const { return children(); } @@ -57,8 +81,7 @@ private: virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); - // We need to allocate a layer whenever we have an overflow clip as RenderTableSection::paintObject does not push rows' clips. - virtual bool requiresLayer() const OVERRIDE { return isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasFilter(); } + virtual bool requiresLayer() const OVERRIDE { return isTransparent() || hasOverflowClip() || hasTransform() || hasHiddenBackface() || hasMask() || hasFilter(); } virtual void paint(PaintInfo&, const LayoutPoint&); @@ -67,6 +90,7 @@ private: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); RenderObjectChildList m_children; + unsigned m_rowIndex : 31; }; inline RenderTableRow* toRenderTableRow(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp index 08a8c9b7d..0651c77af 100644 --- a/Source/WebCore/rendering/RenderTableSection.cpp +++ b/Source/WebCore/rendering/RenderTableSection.cpp @@ -161,11 +161,7 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild return; } - RenderObject* row = new (renderArena()) RenderTableRow(document() /* anonymous table row */); - RefPtr<RenderStyle> newStyle = RenderStyle::create(); - newStyle->inheritFrom(style()); - newStyle->setDisplay(TABLE_ROW); - row->setStyle(newStyle.release()); + RenderObject* row = RenderTableRow::createAnonymousWithParentRenderer(this); addChild(row, beforeChild); row->addChild(child); return; @@ -180,14 +176,15 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild ensureRows(m_cRow); - m_grid[insertionRow].rowRenderer = toRenderTableRow(child); + RenderTableRow* row = toRenderTableRow(child); + m_grid[insertionRow].rowRenderer = row; + row->setRowIndex(insertionRow); if (!beforeChild) setRowLogicalHeightToRowStyleLogicalHeightIfNotRelative(m_grid[insertionRow]); - // If the next renderer is actually wrapped in an anonymous table row, we need to go up and find that. - while (beforeChild && beforeChild->parent() != this) - beforeChild = beforeChild->parent(); + if (beforeChild && beforeChild->parent() != this) + beforeChild = splitAnonymousBoxesAroundChild(beforeChild); ASSERT(!beforeChild || beforeChild->isTableRow()); RenderBox::addChild(child, beforeChild); @@ -225,9 +222,7 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row) unsigned cSpan = cell->colSpan(); Vector<RenderTable::ColumnStruct>& columns = table()->columns(); unsigned nCols = columns.size(); - // addCell should be called only after m_cRow has been incremented. - ASSERT(m_cRow); - unsigned insertionRow = m_cRow - 1; + unsigned insertionRow = row->rowIndex(); // ### mozilla still seems to do the old HTML way, even for strict DTD // (see the annotation on table cell layouting in the CSS specs and the testcase below: @@ -271,7 +266,6 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row) cSpan -= currentSpan; inColSpan = true; } - cell->setRow(insertionRow); cell->setCol(table()->effColToCol(col)); } @@ -327,8 +321,9 @@ int RenderTableSection::calcRowLogicalHeight() RenderTableCell* cell; int spacing = table()->vBorderSpacing(); - - LayoutStateMaintainer statePusher(view()); + + RenderView* viewRenderer = view(); + LayoutStateMaintainer statePusher(viewRenderer); m_rowPos.resize(m_grid.size() + 1); m_rowPos[0] = spacing; @@ -338,7 +333,7 @@ int RenderTableSection::calcRowLogicalHeight() LayoutUnit baselineDescent = 0; // Our base size is the biggest logical height from our cells' styles (excluding row spanning cells). - m_rowPos[r + 1] = max(m_rowPos[r] + m_grid[r].logicalHeight.calcMinValue(0), 0); + m_rowPos[r + 1] = max(m_rowPos[r] + minimumIntValueForLength(m_grid[r].logicalHeight, 0, viewRenderer), 0); Row& row = m_grid[r].row; unsigned totalCols = row.size(); @@ -352,11 +347,11 @@ int RenderTableSection::calcRowLogicalHeight() // FIXME: We are always adding the height of a rowspan to the last rows which doesn't match // other browsers. See webkit.org/b/52185 for example. - if ((cell->row() + cell->rowSpan() - 1) != r) + if ((cell->rowIndex() + cell->rowSpan() - 1) != r) continue; // For row spanning cells, |r| is the last row in the span. - unsigned cellStartRow = cell->row(); + unsigned cellStartRow = cell->rowIndex(); if (cell->hasOverrideHeight()) { if (!statePusher.didPush()) { @@ -366,7 +361,7 @@ int RenderTableSection::calcRowLogicalHeight() } cell->clearIntrinsicPadding(); cell->clearOverrideSize(); - cell->setChildNeedsLayout(true, false); + cell->setChildNeedsLayout(true, MarkOnlyThis); cell->layoutIfNeeded(); } @@ -376,7 +371,7 @@ int RenderTableSection::calcRowLogicalHeight() // find out the baseline EVerticalAlign va = cell->style()->verticalAlign(); if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) { - int baselinePosition = cell->cellBaselinePosition(); + LayoutUnit baselinePosition = cell->cellBaselinePosition(); if (baselinePosition > cell->borderBefore() + cell->paddingBefore()) { m_grid[r].baseline = max(m_grid[r].baseline, baselinePosition - cell->intrinsicPaddingBefore()); baselineDescent = max(baselineDescent, m_rowPos[cellStartRow] + cellLogicalHeight - (baselinePosition - cell->intrinsicPaddingBefore())); @@ -387,7 +382,7 @@ int RenderTableSection::calcRowLogicalHeight() // do we have baseline aligned elements? if (m_grid[r].baseline) // increase rowheight if baseline requires - m_rowPos[r + 1] = max(m_rowPos[r + 1], m_grid[r].baseline + baselineDescent); + m_rowPos[r + 1] = max<int>(m_rowPos[r + 1], m_grid[r].baseline + baselineDescent); // Add the border-spacing to our final position. m_rowPos[r + 1] += m_grid[r].rowRenderer ? spacing : 0; @@ -417,21 +412,17 @@ void RenderTableSection::layout() } } statePusher.pop(); - - if (hasOverflowClip() && !hasLayer()) - updateCachedSizeForOverflowClip(); - setNeedsLayout(false); } -int RenderTableSection::distributeExtraLogicalHeightToPercentRows(int extraLogicalHeight, int totalPercent) +void RenderTableSection::distributeExtraLogicalHeightToPercentRows(int& extraLogicalHeight, int totalPercent) { if (!totalPercent) - return extraLogicalHeight; + return; unsigned totalRows = m_grid.size(); int totalHeight = m_rowPos[totalRows] + extraLogicalHeight; - int add = 0; + int totalLogicalHeightAdded = 0; totalPercent = min(totalPercent, 100); int rowHeight = m_rowPos[1] - m_rowPos[0]; for (unsigned r = 0; r < totalRows; ++r) { @@ -440,56 +431,54 @@ int RenderTableSection::distributeExtraLogicalHeightToPercentRows(int extraLogic // If toAdd is negative, then we don't want to shrink the row (this bug // affected Outlook Web Access). toAdd = max(0, toAdd); - add += toAdd; + totalLogicalHeightAdded += toAdd; extraLogicalHeight -= toAdd; totalPercent -= m_grid[r].logicalHeight.percent(); } ASSERT(totalRows >= 1); if (r < totalRows - 1) rowHeight = m_rowPos[r + 2] - m_rowPos[r + 1]; - m_rowPos[r + 1] += add; + m_rowPos[r + 1] += totalLogicalHeightAdded; } - return extraLogicalHeight; } -int RenderTableSection::distributeExtraLogicalHeightToAutoRows(int extraLogicalHeight, unsigned autoRowsCount) +void RenderTableSection::distributeExtraLogicalHeightToAutoRows(int& extraLogicalHeight, unsigned autoRowsCount) { if (!autoRowsCount) - return extraLogicalHeight; + return; - int add = 0; + int totalLogicalHeightAdded = 0; for (unsigned r = 0; r < m_grid.size(); ++r) { if (autoRowsCount > 0 && m_grid[r].logicalHeight.isAuto()) { // Recomputing |extraLogicalHeightForRow| guarantees that we properly ditribute round |extraLogicalHeight|. int extraLogicalHeightForRow = extraLogicalHeight / autoRowsCount; - add += extraLogicalHeightForRow; + totalLogicalHeightAdded += extraLogicalHeightForRow; extraLogicalHeight -= extraLogicalHeightForRow; --autoRowsCount; } - m_rowPos[r + 1] += add; + m_rowPos[r + 1] += totalLogicalHeightAdded; } - return extraLogicalHeight; } -int RenderTableSection::distributeRemainingExtraLogicalHeight(int extraLogicalHeight) +void RenderTableSection::distributeRemainingExtraLogicalHeight(int& extraLogicalHeight) { unsigned totalRows = m_grid.size(); if (extraLogicalHeight <= 0 || !m_rowPos[totalRows]) - return extraLogicalHeight; + return; // FIXME: m_rowPos[totalRows] - m_rowPos[0] is the total rows' size. int totalRowSize = m_rowPos[totalRows]; - int add = 0; + int totalLogicalHeightAdded = 0; int previousRowPosition = m_rowPos[0]; for (unsigned r = 0; r < totalRows; r++) { // weight with the original height - add += extraLogicalHeight * (m_rowPos[r + 1] - previousRowPosition) / totalRowSize; + totalLogicalHeightAdded += extraLogicalHeight * (m_rowPos[r + 1] - previousRowPosition) / totalRowSize; previousRowPosition = m_rowPos[r + 1]; - m_rowPos[r + 1] += add; + m_rowPos[r + 1] += totalLogicalHeightAdded; } - return extraLogicalHeight; + extraLogicalHeight -= totalLogicalHeightAdded; } int RenderTableSection::distributeExtraLogicalHeightToRows(int extraLogicalHeight) @@ -514,13 +503,13 @@ int RenderTableSection::distributeExtraLogicalHeightToRows(int extraLogicalHeigh } int remainingExtraLogicalHeight = extraLogicalHeight; - remainingExtraLogicalHeight = distributeExtraLogicalHeightToPercentRows(remainingExtraLogicalHeight, totalPercent); - remainingExtraLogicalHeight = distributeExtraLogicalHeightToAutoRows(remainingExtraLogicalHeight, autoRowsCount); - remainingExtraLogicalHeight = distributeRemainingExtraLogicalHeight(remainingExtraLogicalHeight); - return remainingExtraLogicalHeight; + distributeExtraLogicalHeightToPercentRows(remainingExtraLogicalHeight, totalPercent); + distributeExtraLogicalHeightToAutoRows(remainingExtraLogicalHeight, autoRowsCount); + distributeRemainingExtraLogicalHeight(remainingExtraLogicalHeight); + return extraLogicalHeight - remainingExtraLogicalHeight; } -int RenderTableSection::layoutRows(int extraLogicalHeight) +void RenderTableSection::layoutRows() { #ifndef NDEBUG setNeedsLayoutIsForbidden(true); @@ -538,8 +527,6 @@ int RenderTableSection::layoutRows(int extraLogicalHeight) m_overflowingCells.clear(); m_forceSlowPaintPathWithOverflowingCell = false; - extraLogicalHeight = distributeExtraLogicalHeightToRows(extraLogicalHeight); - int hspacing = table()->hBorderSpacing(); int vspacing = table()->vBorderSpacing(); unsigned nEffCols = table()->numEffCols(); @@ -562,7 +549,7 @@ int RenderTableSection::layoutRows(int extraLogicalHeight) if (!cell || cs.inColSpan) continue; - rindx = cell->row(); + rindx = cell->rowIndex(); rHeight = m_rowPos[rindx + cell->rowSpan()] - m_rowPos[rindx] - vspacing; // Force percent height children to lay themselves out again. @@ -586,7 +573,7 @@ int RenderTableSection::layoutRows(int extraLogicalHeight) if (!o->isText() && o->style()->logicalHeight().isPercent() && (flexAllChildren || o->isReplaced() || (o->isBox() && toRenderBox(o)->scrollsOverflow()))) { // Tables with no sections do not flex. if (!o->isTable() || toRenderTable(o)->hasSections()) { - o->setNeedsLayout(true, false); + o->setNeedsLayout(true, MarkOnlyThis); cellChildrenFlex = true; } } @@ -602,7 +589,7 @@ int RenderTableSection::layoutRows(int extraLogicalHeight) while (box != cell) { if (box->normalChildNeedsLayout()) break; - box->setChildNeedsLayout(true, false); + box->setChildNeedsLayout(true, MarkOnlyThis); box = box->containingBlock(); ASSERT(box); if (!box) @@ -613,7 +600,7 @@ int RenderTableSection::layoutRows(int extraLogicalHeight) } if (cellChildrenFlex) { - cell->setChildNeedsLayout(true, false); + cell->setChildNeedsLayout(true, MarkOnlyThis); // Alignment within a cell is based off the calculated // height, which becomes irrelevant once the cell has // been resized based off its percentage. @@ -640,7 +627,7 @@ int RenderTableSection::layoutRows(int extraLogicalHeight) case TEXT_TOP: case TEXT_BOTTOM: case BASELINE: { - int b = cell->cellBaselinePosition(); + LayoutUnit b = cell->cellBaselinePosition(); if (b > cell->borderBefore() + cell->paddingBefore()) intrinsicPaddingBefore = getBaseline(r) - (b - oldIntrinsicPaddingBefore); break; @@ -672,16 +659,26 @@ int RenderTableSection::layoutRows(int extraLogicalHeight) view()->addLayoutDelta(oldCellRect.location() - cell->location()); if (intrinsicPaddingBefore != oldIntrinsicPaddingBefore || intrinsicPaddingAfter != oldIntrinsicPaddingAfter) - cell->setNeedsLayout(true, false); + cell->setNeedsLayout(true, MarkOnlyThis); if (!cell->needsLayout() && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell->logicalTop()) != cell->pageLogicalOffset()) - cell->setChildNeedsLayout(true, false); + cell->setChildNeedsLayout(true, MarkOnlyThis); cell->layoutIfNeeded(); // FIXME: Make pagination work with vertical tables. - if (style()->isHorizontalWritingMode() && view()->layoutState()->pageLogicalHeight() && 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. + if (view()->layoutState()->pageLogicalHeight() && cell->logicalHeight() != rHeight) { + // FIXME: Pagination might have made us change size. For now just shrink or grow the cell to fit without doing a relayout. + // We'll also do a basic increase of the row height to accommodate the cell if it's bigger, but this isn't quite right + // either. It's at least stable though and won't result in an infinite # of relayouts that may never stabilize. + if (cell->logicalHeight() > rHeight) { + unsigned delta = cell->logicalHeight() - rHeight; + for (unsigned rowIndex = rindx + cell->rowSpan(); rowIndex <= totalRows; rowIndex++) + m_rowPos[rowIndex] += delta; + rHeight = cell->logicalHeight(); + } else + cell->setLogicalHeight(rHeight); + } LayoutSize childOffset(cell->location() - oldCellRect.location()); if (childOffset.width() || childOffset.height()) { @@ -738,7 +735,6 @@ int RenderTableSection::layoutRows(int extraLogicalHeight) ASSERT(hasOverflowingCell == this->hasOverflowingCell()); statePusher.pop(); - return height(); } int RenderTableSection::calcOuterBorderBefore() const @@ -954,7 +950,7 @@ LayoutUnit RenderTableSection::firstLineBoxBaseline() const const CellStruct& cs = firstRow.at(i); const RenderTableCell* cell = cs.primaryCell(); if (cell) - firstLineBaseline = max(firstLineBaseline, cell->logicalTop() + cell->paddingBefore() + cell->borderBefore() + cell->contentLogicalHeight(IncludeIntrinsicPadding)); + firstLineBaseline = max(firstLineBaseline, cell->logicalTop() + cell->paddingBefore() + cell->borderBefore() + cell->contentLogicalHeight()); } return firstLineBaseline; @@ -988,15 +984,15 @@ void RenderTableSection::paint(PaintInfo& paintInfo, const LayoutPoint& paintOff static inline bool compareCellPositions(RenderTableCell* elem1, RenderTableCell* elem2) { - return elem1->row() < elem2->row(); + return elem1->rowIndex() < elem2->rowIndex(); } // This comparison is used only when we have overflowing cells as we have an unsorted array to sort. We thus need // to sort both on rows and columns to properly repaint. static inline bool compareCellPositionsWithOverflowingCells(RenderTableCell* elem1, RenderTableCell* elem2) { - if (elem1->row() != elem2->row()) - return elem1->row() < elem2->row(); + if (elem1->rowIndex() != elem2->rowIndex()) + return elem1->rowIndex() < elem2->rowIndex(); return elem1->col() < elem2->col(); } @@ -1222,6 +1218,7 @@ void RenderTableSection::recalcCells() RenderTableRow* tableRow = toRenderTableRow(row); m_grid[insertionRow].rowRenderer = tableRow; + tableRow->setRowIndex(insertionRow); setRowLogicalHeightToRowStyleLogicalHeightIfNotRelative(m_grid[insertionRow]); for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) { @@ -1388,16 +1385,6 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul } -unsigned RenderTableSection::rowIndexForRenderer(const RenderTableRow* row) const -{ - for (size_t i = 0; i < m_grid.size(); ++i) { - if (m_grid[i].rowRenderer == row) - return i; - } - ASSERT_NOT_REACHED(); - return 0; -} - void RenderTableSection::removeCachedCollapsedBorders(const RenderTableCell* cell) { if (!table()->collapseBorders()) @@ -1421,4 +1408,12 @@ CollapsedBorderValue& RenderTableSection::cachedCollapsedBorder(const RenderTabl return it->second; } +RenderTableSection* RenderTableSection::createAnonymousWithParentRenderer(const RenderObject* parent) +{ + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE_ROW_GROUP); + RenderTableSection* newSection = new (parent->renderArena()) RenderTableSection(parent->document() /* is anonymous */); + newSection->setStyle(newStyle.release()); + return newSection; +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderTableSection.h b/Source/WebCore/rendering/RenderTableSection.h index 8df74f06f..dcdc13490 100644 --- a/Source/WebCore/rendering/RenderTableSection.h +++ b/Source/WebCore/rendering/RenderTableSection.h @@ -73,7 +73,7 @@ public: void setCellLogicalWidths(); int calcRowLogicalHeight(); - int layoutRows(int logicalHeight); + void layoutRows(); RenderTable* table() const { return toRenderTable(parent()); } @@ -152,12 +152,20 @@ public: void rowLogicalHeightChanged(unsigned rowIndex); - unsigned rowIndexForRenderer(const RenderTableRow*) const; - void removeCachedCollapsedBorders(const RenderTableCell*); void setCachedCollapsedBorder(const RenderTableCell*, CollapsedBorderSide, CollapsedBorderValue); CollapsedBorderValue& cachedCollapsedBorder(const RenderTableCell*, CollapsedBorderSide); + // distributeExtraLogicalHeightToRows methods return the *consumed* extra logical height. + // FIXME: We may want to introduce a structure holding the in-flux layout information. + int distributeExtraLogicalHeightToRows(int extraLogicalHeight); + + static RenderTableSection* createAnonymousWithParentRenderer(const RenderObject*); + virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const OVERRIDE + { + return createAnonymousWithParentRenderer(parent); + } + protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); @@ -185,12 +193,9 @@ private: void ensureRows(unsigned); - // Those methods return the remaining extra logical height. - // FIXME: We may want to introduce a structure holding the in-flux layout information. - int distributeExtraLogicalHeightToRows(int extraLogicalHeight); - int distributeExtraLogicalHeightToPercentRows(int extraLogicalHeight, int totalPercent); - int distributeExtraLogicalHeightToAutoRows(int extraLogicalHeight, unsigned autoRowsCount); - int distributeRemainingExtraLogicalHeight(int extraLogicalHeight); + void distributeExtraLogicalHeightToPercentRows(int& extraLogicalHeight, int totalPercent); + void distributeExtraLogicalHeightToAutoRows(int& extraLogicalHeight, unsigned autoRowsCount); + void distributeRemainingExtraLogicalHeight(int& extraLogicalHeight); bool hasOverflowingCell() const { return m_overflowingCells.size() || m_forceSlowPaintPathWithOverflowingCell; } diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp index d497a33d6..063efd5b8 100644 --- a/Source/WebCore/rendering/RenderText.cpp +++ b/Source/WebCore/rendering/RenderText.cpp @@ -53,6 +53,15 @@ using namespace Unicode; namespace WebCore { +class SameSizeAsRenderText : public RenderObject { + uint32_t bitfields : 16; + float widths[4]; + String text; + void* pointers[2]; +}; + +COMPILE_ASSERT(sizeof(RenderText) == sizeof(SameSizeAsRenderText), RenderText_should_stay_small); + class SecureTextTimer; typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap; static SecureTextTimerMap* gSecureTextTimers = 0; @@ -126,22 +135,23 @@ static void makeCapitalized(String* string, UChar previous) RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str) : RenderObject(node) - , m_minWidth(-1) - , m_text(str) - , m_firstTextBox(0) - , m_lastTextBox(0) - , m_maxWidth(-1) - , m_beginMinWidth(0) - , m_endMinWidth(0) , m_hasTab(false) , m_linesDirty(false) , m_containsReversedText(false) - , m_isAllASCII(m_text.containsOnlyASCII()) , m_knownToHaveNoOverflowAndNoFallbackFonts(false) , m_needsTranscoding(false) + , m_minWidth(-1) + , m_maxWidth(-1) + , m_beginMinWidth(0) + , m_endMinWidth(0) + , m_text(str) + , m_firstTextBox(0) + , m_lastTextBox(0) { ASSERT(m_text); + m_isAllASCII = m_text.containsOnlyASCII(); + m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath(); setIsText(); view()->frameView()->incrementVisuallyNonEmptyCharacterCount(m_text.length()); @@ -201,10 +211,8 @@ void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE; ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE; - if (needsResetText || oldTransform != newStyle->textTransform() || oldSecurity != newStyle->textSecurity()) { - if (RefPtr<StringImpl> textToTransform = originalText()) - setText(textToTransform.release(), true); - } + if (needsResetText || oldTransform != newStyle->textTransform() || oldSecurity != newStyle->textSecurity()) + transformText(); } void RenderText::removeAndDestroyTextBoxes() @@ -312,7 +320,7 @@ void RenderText::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumu static FloatRect localQuadForTextBox(InlineTextBox* box, unsigned start, unsigned end, bool useSelectionHeight) { unsigned realEnd = min(box->end() + 1, end); - IntRect r = box->localSelectionRect(start, realEnd); + LayoutRect r = box->localSelectionRect(start, realEnd); if (r.height()) { if (!useSelectionHeight) { // Change the height and y position (or width and x for vertical text) @@ -347,7 +355,7 @@ void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, u if (start <= box->start() && box->end() < end) { FloatRect r = box->calculateBoundaries(); if (useSelectionHeight) { - IntRect selectionRect = box->localSelectionRect(start, end); + LayoutRect selectionRect = box->localSelectionRect(start, end); if (box->isHorizontal()) { r.setHeight(selectionRect.height()); r.setY(selectionRect.y()); @@ -430,8 +438,7 @@ void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start, if (start <= box->start() && box->end() < end) { FloatRect r = box->calculateBoundaries(); if (useSelectionHeight) { - // FIXME: localSelectionRect should switch to return FloatRect soon with the subpixellayout branch. - IntRect selectionRect = box->localSelectionRect(start, end); + LayoutRect selectionRect = box->localSelectionRect(start, end); if (box->isHorizontal()) { r.setHeight(selectionRect.height()); r.setY(selectionRect.y()); @@ -754,6 +761,7 @@ ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len run.setCharactersLength(textLength() - start); ASSERT(run.charactersLength() >= run.length()); + run.setCharacterScanForCodePath(!canUseSimpleFontCodePath()); run.setAllowTabs(allowTabs()); run.setXPos(xPos); return f.width(run, fallbackFonts, glyphOverflow); @@ -1239,6 +1247,12 @@ void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, setText(text, force); } +void RenderText::transformText() +{ + if (RefPtr<StringImpl> textToTransform = originalText()) + setText(textToTransform.release(), true); +} + static inline bool isInlineFlowOrEmptyText(const RenderObject* o) { if (o->isRenderInline()) @@ -1318,6 +1332,7 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text) ASSERT(!isBR() || (textLength() == 1 && m_text[0] == '\n')); m_isAllASCII = m_text.containsOnlyASCII(); + m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath(); } void RenderText::secureText(UChar mask) @@ -1461,6 +1476,7 @@ float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, run.setCharactersLength(textLength() - from); ASSERT(run.charactersLength() >= run.length()); + run.setCharacterScanForCodePath(!canUseSimpleFontCodePath()); run.setAllowTabs(allowTabs()); run.setXPos(xPos); w = f.width(run, fallbackFonts, glyphOverflow); @@ -1469,9 +1485,9 @@ float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, return w; } -LayoutRect RenderText::linesBoundingBox() const +IntRect RenderText::linesBoundingBox() const { - LayoutRect result; + IntRect result; ASSERT(!firstTextBox() == !lastTextBox()); // Either both are null or both exist. if (firstTextBox() && lastTextBox()) { @@ -1503,8 +1519,8 @@ LayoutRect RenderText::linesVisualOverflowBoundingBox() const return LayoutRect(); // Return the width of the minimal left side and the maximal right side. - LayoutUnit logicalLeftSide = numeric_limits<LayoutUnit>::max(); - LayoutUnit logicalRightSide = numeric_limits<LayoutUnit>::min(); + LayoutUnit logicalLeftSide = MAX_LAYOUT_UNIT; + LayoutUnit logicalRightSide = MIN_LAYOUT_UNIT; for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) { logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow()); logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow()); @@ -1548,7 +1564,7 @@ LayoutRect RenderText::selectionRectForRepaint(RenderBoxModelObject* repaintCont // Now calculate startPos and endPos for painting selection. // We include a selection while endPos > 0 - LayoutUnit startPos, endPos; + int startPos, endPos; if (selectionState() == SelectionInside) { // We are fully selected. startPos = 0; @@ -1781,6 +1797,13 @@ int RenderText::nextOffset(int current) const return result; } +bool RenderText::computeCanUseSimpleFontCodePath() const +{ + if (isAllASCII()) + return true; + return Font::characterRangeCodePath(characters(), length()) == Font::Simple; +} + #ifndef NDEBUG void RenderText::checkConsistency() const diff --git a/Source/WebCore/rendering/RenderText.h b/Source/WebCore/rendering/RenderText.h index e2c6a8a69..9043b0954 100644 --- a/Source/WebCore/rendering/RenderText.h +++ b/Source/WebCore/rendering/RenderText.h @@ -24,6 +24,7 @@ #define RenderText_h #include "RenderObject.h" +#include "RenderView.h" #include <wtf/Forward.h> namespace WebCore { @@ -82,23 +83,25 @@ public: float& beginMaxW, float& endMaxW, float& minW, float& maxW, bool& stripFrontSpaces); - virtual LayoutRect linesBoundingBox() const; + virtual IntRect linesBoundingBox() const; LayoutRect linesVisualOverflowBoundingBox() const; FloatPoint firstRunOrigin() const; float firstRunX() const; float firstRunY() const; - void setText(PassRefPtr<StringImpl>, bool force = false); + virtual void setText(PassRefPtr<StringImpl>, bool force = false); void setTextWithOffset(PassRefPtr<StringImpl>, unsigned offset, unsigned len, bool force = false); + virtual void transformText(); + virtual bool canBeSelectionLeaf() const { return true; } virtual void setSelectionState(SelectionState s); virtual LayoutRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent = true); virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0); - virtual LayoutUnit marginLeft() const { return style()->marginLeft().calcMinValue(0); } - virtual LayoutUnit marginRight() const { return style()->marginRight().calcMinValue(0); } + virtual LayoutUnit marginLeft() const { return minimumValueForLength(style()->marginLeft(), 0, view()); } + virtual LayoutUnit marginRight() const { return minimumValueForLength(style()->marginRight(), 0, view()); } virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const; @@ -126,7 +129,8 @@ public: virtual void computePreferredLogicalWidths(float leadWidth); bool isAllCollapsibleWhitespace(); - + + bool canUseSimpleFontCodePath() const { return m_canUseSimpleFontCodePath; } bool knownToHaveNoOverflowAndNoFallbackFonts() const { return m_knownToHaveNoOverflowAndNoFallbackFonts; } void removeAndDestroyTextBoxes(); @@ -145,6 +149,8 @@ protected: private: void computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow&); + bool computeCanUseSimpleFontCodePath() const; + // Make length() private so that callers that have a RenderText* // will use the more efficient textLength() instead, while // callers with a RenderObject* can continue to use length(). @@ -160,20 +166,9 @@ private: bool isAllASCII() const { return m_isAllASCII; } void updateNeedsTranscoding(); - inline void transformText(String&) const; void secureText(UChar mask); - float m_minWidth; // here to minimize padding in 64-bit. - - String m_text; - - InlineTextBox* m_firstTextBox; - InlineTextBox* m_lastTextBox; - - float m_maxWidth; - float m_beginMinWidth; - float m_endMinWidth; - + // We put the bitfield first to minimize padding on 64-bit. bool m_hasBreakableChar : 1; // Whether or not we can be broken into multiple lines. bool m_hasBreak : 1; // Whether or not we have a hard break (e.g., <pre> with '\n'). bool m_hasTab : 1; // Whether or not we have a variable width tab character (e.g., <pre> with '\t'). @@ -185,8 +180,19 @@ private: // or removed). bool m_containsReversedText : 1; bool m_isAllASCII : 1; + bool m_canUseSimpleFontCodePath : 1; mutable bool m_knownToHaveNoOverflowAndNoFallbackFonts : 1; bool m_needsTranscoding : 1; + + float m_minWidth; + float m_maxWidth; + float m_beginMinWidth; + float m_endMinWidth; + + String m_text; + + InlineTextBox* m_firstTextBox; + InlineTextBox* m_lastTextBox; }; inline RenderText* toRenderText(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp index 2b311f18e..ddc647570 100644 --- a/Source/WebCore/rendering/RenderTextControl.cpp +++ b/Source/WebCore/rendering/RenderTextControl.cpp @@ -291,7 +291,7 @@ RenderObject* RenderTextControl::layoutSpecialExcludedChild(bool relayoutChildre // The markParents arguments should be false because this function is // called from layout() of the parent and the placeholder layout doesn't // affect the parent layout. - placeholderRenderer->setChildNeedsLayout(true, false); + placeholderRenderer->setChildNeedsLayout(true, MarkOnlyThis); } return placeholderRenderer; } diff --git a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp index e7ecedfa6..229fed994 100644 --- a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -25,7 +25,6 @@ #include "RenderTextControlSingleLine.h" #include "CSSFontSelector.h" -#include "CSSStyleSelector.h" #include "CSSValueKeywords.h" #include "Chrome.h" #include "Frame.h" @@ -43,6 +42,7 @@ #include "SearchPopupMenu.h" #include "Settings.h" #include "SimpleFontData.h" +#include "StyleResolver.h" #include "TextControlInnerElements.h" using namespace std; @@ -213,13 +213,7 @@ void RenderTextControlSingleLine::layout() // and type=search if the text height is taller than the contentHeight() // because of compability. - LayoutUnit oldHeight = height(); - computeLogicalHeight(); - - LayoutUnit oldWidth = width(); - computeLogicalWidth(); - - bool relayoutChildren = oldHeight != height() || oldWidth != width(); + RenderBlock::layoutBlock(false); RenderBox* innerTextRenderer = innerTextElement()->renderBox(); ASSERT(innerTextRenderer); @@ -234,7 +228,8 @@ void RenderTextControlSingleLine::layout() LayoutUnit heightLimit = (inputElement()->isSearchField() || !container) ? height() : contentHeight(); if (currentHeight > heightLimit) { if (desiredHeight != currentHeight) - relayoutChildren = true; + setNeedsLayout(true, MarkOnlyThis); + innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed)); m_desiredInnerTextHeight = desiredHeight; if (innerBlockRenderer) @@ -246,15 +241,17 @@ void RenderTextControlSingleLine::layout() LayoutUnit containerHeight = containerRenderer->height(); if (containerHeight > heightLimit) { containerRenderer->style()->setHeight(Length(heightLimit, Fixed)); - relayoutChildren = true; + setNeedsLayout(true, MarkOnlyThis); } else if (containerRenderer->height() < contentHeight()) { containerRenderer->style()->setHeight(Length(contentHeight(), Fixed)); - relayoutChildren = true; + setNeedsLayout(true, MarkOnlyThis); } else containerRenderer->style()->setHeight(Length(containerHeight, Fixed)); } - RenderBlock::layoutBlock(relayoutChildren); + // If we need another layout pass, we have changed one of children's height so we need to relayout them. + if (needsLayout()) + RenderBlock::layoutBlock(true); // Center the child block vertically currentHeight = innerTextRenderer->height(); @@ -282,6 +279,7 @@ void RenderTextControlSingleLine::layout() if (RenderBox* placeholderBox = placeholderElement ? placeholderElement->renderBox() : 0) { placeholderBox->style()->setWidth(Length(innerTextRenderer->width() - placeholderBox->borderAndPaddingWidth(), Fixed)); placeholderBox->style()->setHeight(Length(innerTextRenderer->height() - placeholderBox->borderAndPaddingHeight(), Fixed)); + bool placeholderBoxHadLayout = placeholderBox->everHadLayout(); placeholderBox->layoutIfNeeded(); LayoutPoint textOffset = innerTextRenderer->location(); if (innerBlockElement() && innerBlockElement()->renderBox()) @@ -289,6 +287,12 @@ void RenderTextControlSingleLine::layout() if (containerRenderer) textOffset += toLayoutSize(containerRenderer->location()); placeholderBox->setLocation(textOffset); + + if (!placeholderBoxHadLayout && placeholderBox->checkForRepaintDuringLayout()) { + // This assumes a shadow tree without floats. If floats are added, the + // logic should be shared with RenderBlock::layoutBlockChild. + placeholderBox->repaint(); + } } } @@ -370,7 +374,7 @@ bool RenderTextControlSingleLine::hasControlClip() const LayoutRect RenderTextControlSingleLine::controlClipRect(const LayoutPoint& additionalOffset) const { ASSERT(hasControlClip()); - LayoutRect clipRect = LayoutRect(containerElement()->renderBox()->frameRect()); + LayoutRect clipRect = unionRect(contentBoxRect(), containerElement()->renderBox()->frameRect()); clipRect.moveBy(additionalOffset); return clipRect; } @@ -670,7 +674,7 @@ void RenderTextControlSingleLine::setTextFromItem(unsigned listIndex) FontSelector* RenderTextControlSingleLine::fontSelector() const { - return document()->styleSelector()->fontSelector(); + return document()->styleResolver()->fontSelector(); } HostWindow* RenderTextControlSingleLine::hostWindow() const diff --git a/Source/WebCore/rendering/RenderTextFragment.cpp b/Source/WebCore/rendering/RenderTextFragment.cpp index 1f267cde4..9f497d344 100644 --- a/Source/WebCore/rendering/RenderTextFragment.cpp +++ b/Source/WebCore/rendering/RenderTextFragment.cpp @@ -33,7 +33,6 @@ RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str, int startOff , m_start(startOffset) , m_end(length) , m_firstLetter(0) - , m_allowFragmentReset(true) { } @@ -43,7 +42,6 @@ RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str) , m_end(str ? str->length() : 0) , m_contentString(str) , m_firstLetter(0) - , m_allowFragmentReset(true) { } @@ -62,9 +60,7 @@ PassRefPtr<StringImpl> RenderTextFragment::originalText() const void RenderTextFragment::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - m_allowFragmentReset = false; RenderText::styleDidChange(diff, oldStyle); - m_allowFragmentReset = true; if (RenderBlock* block = blockForAccompanyingFirstLetter()) { block->style()->removeCachedPseudoStyle(FIRST_LETTER); @@ -79,25 +75,30 @@ void RenderTextFragment::willBeDestroyed() RenderText::willBeDestroyed(); } -void RenderTextFragment::setTextInternal(PassRefPtr<StringImpl> text) +void RenderTextFragment::setText(PassRefPtr<StringImpl> text, bool force) { - RenderText::setTextInternal(text); - - if (m_allowFragmentReset) { - m_start = 0; - m_end = textLength(); - if (m_firstLetter) { - ASSERT(!m_contentString); - m_firstLetter->destroy(); - m_firstLetter = 0; - if (Node* t = node()) { - ASSERT(!t->renderer()); - t->setRenderer(this); - } + RenderText::setText(text, force); + + m_start = 0; + m_end = textLength(); + if (m_firstLetter) { + ASSERT(!m_contentString); + m_firstLetter->destroy(); + m_firstLetter = 0; + if (Node* t = node()) { + ASSERT(!t->renderer()); + t->setRenderer(this); } } } +void RenderTextFragment::transformText() +{ + // Don't reset first-letter here because we are only transforming the truncated fragment. + if (RefPtr<StringImpl> textToTransform = originalText()) + RenderText::setText(textToTransform.release(), true); +} + UChar RenderTextFragment::previousCharacter() const { if (start()) { diff --git a/Source/WebCore/rendering/RenderTextFragment.h b/Source/WebCore/rendering/RenderTextFragment.h index 426276fe0..b7f3b0e9a 100644 --- a/Source/WebCore/rendering/RenderTextFragment.h +++ b/Source/WebCore/rendering/RenderTextFragment.h @@ -39,6 +39,8 @@ public: virtual bool isTextFragment() const { return true; } + virtual bool canBeSelectionLeaf() const OVERRIDE { return node() && node()->rendererIsEditable(); } + unsigned start() const { return m_start; } unsigned end() const { return m_end; } @@ -48,13 +50,16 @@ public: StringImpl* contentString() const { return m_contentString.get(); } virtual PassRefPtr<StringImpl> originalText() const; + virtual void setText(PassRefPtr<StringImpl>, bool force = false) OVERRIDE; + + virtual void transformText() OVERRIDE; + protected: virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); private: virtual void willBeDestroyed(); - virtual void setTextInternal(PassRefPtr<StringImpl>); virtual UChar previousCharacter() const; RenderBlock* blockForAccompanyingFirstLetter() const; @@ -62,7 +67,6 @@ private: unsigned m_end; RefPtr<StringImpl> m_contentString; RenderObject* m_firstLetter; - bool m_allowFragmentReset; }; inline RenderTextFragment* toRenderTextFragment(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderTheme.cpp b/Source/WebCore/rendering/RenderTheme.cpp index 8fd2d6c8b..585385f1b 100644 --- a/Source/WebCore/rendering/RenderTheme.cpp +++ b/Source/WebCore/rendering/RenderTheme.cpp @@ -24,6 +24,7 @@ #include "CSSValueKeywords.h" #include "Document.h" +#include "FileList.h" #include "FileSystem.h" #include "FloatConversion.h" #include "FocusController.h" @@ -71,7 +72,7 @@ RenderTheme::RenderTheme() { } -void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e, +void RenderTheme::adjustStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e, bool UAHasAppearance, const BorderData& border, const FillLayer& background, const Color& backgroundColor) { // Force inline and table display styles to be inline-block (except for table- which is block) @@ -100,7 +101,6 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El #if USE(NEW_THEME) switch (part) { - case ListButtonPart: case CheckboxPart: case InnerSpinButtonPart: case RadioPart: @@ -183,48 +183,47 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El switch (style->appearance()) { #if !USE(NEW_THEME) case CheckboxPart: - return adjustCheckboxStyle(selector, style, e); + return adjustCheckboxStyle(styleResolver, style, e); case RadioPart: - return adjustRadioStyle(selector, style, e); + return adjustRadioStyle(styleResolver, style, e); case PushButtonPart: case SquareButtonPart: - case ListButtonPart: case DefaultButtonPart: case ButtonPart: - return adjustButtonStyle(selector, style, e); + return adjustButtonStyle(styleResolver, style, e); case InnerSpinButtonPart: - return adjustInnerSpinButtonStyle(selector, style, e); + return adjustInnerSpinButtonStyle(styleResolver, style, e); #endif case TextFieldPart: - return adjustTextFieldStyle(selector, style, e); + return adjustTextFieldStyle(styleResolver, style, e); case TextAreaPart: - return adjustTextAreaStyle(selector, style, e); + return adjustTextAreaStyle(styleResolver, style, e); case MenulistPart: - return adjustMenuListStyle(selector, style, e); + return adjustMenuListStyle(styleResolver, style, e); case MenulistButtonPart: - return adjustMenuListButtonStyle(selector, style, e); + return adjustMenuListButtonStyle(styleResolver, style, e); case MediaSliderPart: case MediaVolumeSliderPart: case MediaFullScreenVolumeSliderPart: case SliderHorizontalPart: case SliderVerticalPart: - return adjustSliderTrackStyle(selector, style, e); + return adjustSliderTrackStyle(styleResolver, style, e); case SliderThumbHorizontalPart: case SliderThumbVerticalPart: - return adjustSliderThumbStyle(selector, style, e); + return adjustSliderThumbStyle(styleResolver, style, e); case SearchFieldPart: - return adjustSearchFieldStyle(selector, style, e); + return adjustSearchFieldStyle(styleResolver, style, e); case SearchFieldCancelButtonPart: - return adjustSearchFieldCancelButtonStyle(selector, style, e); + return adjustSearchFieldCancelButtonStyle(styleResolver, style, e); case SearchFieldDecorationPart: - return adjustSearchFieldDecorationStyle(selector, style, e); + return adjustSearchFieldDecorationStyle(styleResolver, style, e); case SearchFieldResultsDecorationPart: - return adjustSearchFieldResultsDecorationStyle(selector, style, e); + return adjustSearchFieldResultsDecorationStyle(styleResolver, style, e); case SearchFieldResultsButtonPart: - return adjustSearchFieldResultsButtonStyle(selector, style, e); + return adjustSearchFieldResultsButtonStyle(styleResolver, style, e); #if ENABLE(PROGRESS_TAG) case ProgressBarPart: - return adjustProgressBarStyle(selector, style, e); + return adjustProgressBarStyle(styleResolver, style, e); #endif #if ENABLE(METER_TAG) case MeterPart: @@ -232,18 +231,18 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El case ContinuousCapacityLevelIndicatorPart: case DiscreteCapacityLevelIndicatorPart: case RatingLevelIndicatorPart: - return adjustMeterStyle(selector, style, e); + return adjustMeterStyle(styleResolver, style, e); #endif #if ENABLE(INPUT_SPEECH) case InputSpeechButtonPart: - return adjustInputFieldSpeechButtonStyle(selector, style, e); + return adjustInputFieldSpeechButtonStyle(styleResolver, style, e); #endif default: break; } } -bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const LayoutRect& r) +bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { // If painting is disabled, but we aren't updating control tints, then just bail. // If we are updating control tints, just schedule a repaint if the theme supports tinting @@ -264,7 +263,6 @@ bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const Layou case RadioPart: case PushButtonPart: case SquareButtonPart: - case ListButtonPart: case DefaultButtonPart: case ButtonPart: case InnerSpinButtonPart: @@ -284,7 +282,6 @@ bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const Layou return paintRadio(o, paintInfo, r); case PushButtonPart: case SquareButtonPart: - case ListButtonPart: case DefaultButtonPart: case ButtonPart: return paintButton(o, paintInfo, r); @@ -311,7 +308,8 @@ bool RenderTheme::paint(RenderObject* o, const PaintInfo& paintInfo, const Layou case SliderThumbHorizontalPart: case SliderThumbVerticalPart: return paintSliderThumb(o, paintInfo, r); - case MediaFullscreenButtonPart: + case MediaEnterFullscreenButtonPart: + case MediaExitFullscreenButtonPart: return paintMediaFullscreenButton(o, paintInfo, r); case MediaPlayButtonPart: return paintMediaPlayButton(o, paintInfo, r); @@ -394,7 +392,6 @@ bool RenderTheme::paintBorderOnly(RenderObject* o, const PaintInfo& paintInfo, c case RadioPart: case PushButtonPart: case SquareButtonPart: - case ListButtonPart: case DefaultButtonPart: case ButtonPart: case MenulistPart: @@ -442,7 +439,6 @@ bool RenderTheme::paintDecorations(RenderObject* o, const PaintInfo& paintInfo, case RadioPart: case PushButtonPart: case SquareButtonPart: - case ListButtonPart: case DefaultButtonPart: case ButtonPart: case MenulistPart: @@ -505,13 +501,13 @@ String RenderTheme::formatMediaControlsRemainingTime(float currentTime, float du return formatMediaControlsTime(currentTime - duration); } -LayoutPoint RenderTheme::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const LayoutSize& size) const +IntPoint RenderTheme::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const { - LayoutUnit y = -size.height(); + int y = -size.height(); FloatPoint absPoint = muteButtonBox->localToAbsolute(FloatPoint(muteButtonBox->pixelSnappedOffsetLeft(), y), true, true); if (absPoint.y() < 0) y = muteButtonBox->height(); - return LayoutPoint(0, y); + return IntPoint(0, y); } #endif @@ -617,6 +613,13 @@ Color RenderTheme::platformInactiveListBoxSelectionForegroundColor() const return platformInactiveSelectionForegroundColor(); } +#if ENABLE(CALENDAR_PICKER) +CString RenderTheme::extraCalendarPickerStyleSheet() +{ + return CString(); +} +#endif + LayoutUnit RenderTheme::baselinePosition(const RenderObject* o) const { if (!o->isBox()) @@ -667,7 +670,7 @@ bool RenderTheme::isControlStyled(const RenderStyle* style, const BorderData& bo } } -void RenderTheme::adjustRepaintRect(const RenderObject* o, LayoutRect& r) +void RenderTheme::adjustRepaintRect(const RenderObject* o, IntRect& r) { #if USE(NEW_THEME) m_theme->inflateControlPaintRect(o->style()->appearance(), controlStatesForRenderer(o), r, o->style()->effectiveZoom()); @@ -848,7 +851,7 @@ bool RenderTheme::isDefault(const RenderObject* o) const #if !USE(NEW_THEME) -void RenderTheme::adjustCheckboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderTheme::adjustCheckboxStyle(StyleResolver*, RenderStyle* style, Element*) const { // A summary of the rules for checkbox designed to match WinIE: // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.) @@ -865,7 +868,7 @@ void RenderTheme::adjustCheckboxStyle(CSSStyleSelector*, RenderStyle* style, Ele style->setBoxShadow(nullptr); } -void RenderTheme::adjustRadioStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderTheme::adjustRadioStyle(StyleResolver*, RenderStyle* style, Element*) const { // A summary of the rules for checkbox designed to match WinIE: // width/height - honored (WinIE actually scales its control for small widths, but lets it overflow for small heights.) @@ -882,34 +885,34 @@ void RenderTheme::adjustRadioStyle(CSSStyleSelector*, RenderStyle* style, Elemen style->setBoxShadow(nullptr); } -void RenderTheme::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderTheme::adjustButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { // Most platforms will completely honor all CSS, and so we have no need to adjust the style // at all by default. We will still allow the theme a crack at setting up a desired vertical size. setButtonSize(style); } -void RenderTheme::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const { } #endif -void RenderTheme::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const { } -void RenderTheme::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const { } -void RenderTheme::adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const { } #if ENABLE(INPUT_SPEECH) -void RenderTheme::adjustInputFieldSpeechButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const +void RenderTheme::adjustInputFieldSpeechButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const { - RenderInputSpeech::adjustInputFieldSpeechButtonStyle(selector, style, element); + RenderInputSpeech::adjustInputFieldSpeechButtonStyle(styleResolver, style, element); } bool RenderTheme::paintInputFieldSpeechButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) @@ -919,12 +922,12 @@ bool RenderTheme::paintInputFieldSpeechButton(RenderObject* object, const PaintI #endif #if ENABLE(METER_TAG) -void RenderTheme::adjustMeterStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderTheme::adjustMeterStyle(StyleResolver*, RenderStyle* style, Element*) const { style->setBoxShadow(nullptr); } -LayoutSize RenderTheme::meterSizeForBounds(const RenderMeter*, const LayoutRect& bounds) const +IntSize RenderTheme::meterSizeForBounds(const RenderMeter*, const IntRect& bounds) const { return bounds.size(); } @@ -952,7 +955,7 @@ double RenderTheme::animationDurationForProgressBar(RenderProgress*) const return 0; } -void RenderTheme::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const { } #endif @@ -962,15 +965,15 @@ bool RenderTheme::shouldHaveSpinButton(HTMLInputElement* inputElement) const return inputElement->isSteppable() && !inputElement->isRangeControl(); } -void RenderTheme::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const { } -void RenderTheme::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustSliderTrackStyle(StyleResolver*, RenderStyle*, Element*) const { } -void RenderTheme::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderTheme::adjustSliderThumbStyle(StyleResolver*, RenderStyle* style, Element*) const { adjustSliderThumbSize(style); } @@ -979,23 +982,23 @@ void RenderTheme::adjustSliderThumbSize(RenderStyle*) const { } -void RenderTheme::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const { } -void RenderTheme::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const { } -void RenderTheme::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const { } -void RenderTheme::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const { } -void RenderTheme::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderTheme::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const { } @@ -1137,18 +1140,18 @@ String RenderTheme::fileListDefaultLabel(bool multipleFilesAllowed) const return fileButtonNoFileSelectedLabel(); } -String RenderTheme::fileListNameForWidth(const Vector<String>& filenames, const Font& font, int width, bool multipleFilesAllowed) const +String RenderTheme::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const { if (width <= 0) return String(); String string; - if (filenames.isEmpty()) + if (fileList->isEmpty()) string = fileListDefaultLabel(multipleFilesAllowed); - else if (filenames.size() == 1) - string = pathGetFileName(filenames[0]); + else if (fileList->length() == 1) + string = fileList->item(0)->name(); else - return StringTruncator::rightTruncate(multipleFileUploadText(filenames.size()), width, font, StringTruncator::EnableRoundingHacks); + return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks); return StringTruncator::centerTruncate(string, width, font, StringTruncator::EnableRoundingHacks); } diff --git a/Source/WebCore/rendering/RenderTheme.h b/Source/WebCore/rendering/RenderTheme.h index 44ef1241e..e3e71475f 100644 --- a/Source/WebCore/rendering/RenderTheme.h +++ b/Source/WebCore/rendering/RenderTheme.h @@ -36,6 +36,7 @@ namespace WebCore { class Element; +class FileList; class HTMLInputElement; class PopupMenu; class RenderMenuList; @@ -70,13 +71,13 @@ public: // metrics and defaults given the contents of the style. This includes sophisticated operations like // selection of control size based off the font, the disabling of appearance when certain other properties like // "border" are set, or if the appearance is not supported by the theme. - void adjustStyle(CSSStyleSelector*, RenderStyle*, Element*, bool UAHasAppearance, + void adjustStyle(StyleResolver*, RenderStyle*, Element*, bool UAHasAppearance, const BorderData&, const FillLayer&, const Color& backgroundColor); // This method is called to paint the widget as a background of the RenderObject. A widget's foreground, e.g., the // text of a button, is always rendered by the engine itself. The boolean return value indicates // whether the CSS border/background should also be painted. - bool paint(RenderObject*, const PaintInfo&, const LayoutRect&); + bool paint(RenderObject*, const PaintInfo&, const IntRect&); bool paintBorderOnly(RenderObject*, const PaintInfo&, const IntRect&); bool paintDecorations(RenderObject*, const PaintInfo&, const IntRect&); @@ -93,6 +94,9 @@ public: #if ENABLE(FULLSCREEN_API) virtual String extraFullScreenStyleSheet() { return String(); }; #endif +#if ENABLE(CALENDAR_PICKER) + virtual CString extraCalendarPickerStyleSheet(); +#endif // A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of @@ -114,7 +118,7 @@ public: // Some controls may spill out of their containers (e.g., the check on an OS X checkbox). When these controls repaint, // the theme needs to communicate this inflated rect to the engine so that it can invalidate the whole control. - virtual void adjustRepaintRect(const RenderObject*, LayoutRect&); + virtual void adjustRepaintRect(const RenderObject*, IntRect&); // This method is called whenever a relevant state changes on a particular themed object, e.g., the mouse becomes pressed // or a control becomes disabled. @@ -130,6 +134,9 @@ public: // A method asking if the theme's controls actually care about redrawing when hovered. virtual bool supportsHover(const RenderStyle*) const { return false; } + // A method asking if the platform is able to show datalist suggestions for a given input type. + virtual bool supportsDataListUI(const AtomicString&) const { return false; } + // Text selection colors. Color activeSelectionBackgroundColor() const; Color inactiveSelectionBackgroundColor() const; @@ -176,7 +183,7 @@ public: virtual ScrollbarControlSize scrollbarControlSizeForPart(ControlPart) { return RegularScrollbar; } // Method for painting the caps lock indicator - virtual bool paintCapsLockIndicator(RenderObject*, const PaintInfo&, const LayoutRect&) { return 0; }; + virtual bool paintCapsLockIndicator(RenderObject*, const PaintInfo&, const IntRect&) { return 0; }; #if ENABLE(PROGRESS_TAG) // Returns the repeat interval of the animation for the progress bar. @@ -198,11 +205,11 @@ public: virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const; // Returns the media volume slider container's offset from the mute button. - virtual LayoutPoint volumeSliderOffsetFromMuteButton(RenderBox*, const LayoutSize&) const; + virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const; #endif #if ENABLE(METER_TAG) - virtual LayoutSize meterSizeForBounds(const RenderMeter*, const LayoutRect&) const; + virtual IntSize meterSizeForBounds(const RenderMeter*, const IntRect&) const; virtual bool supportsMeter(ControlPart) const; #endif @@ -215,7 +222,7 @@ public: virtual bool popsMenuBySpaceOrReturn() const { return false; } virtual String fileListDefaultLabel(bool multipleFilesAllowed) const; - virtual String fileListNameForWidth(const Vector<String>& filenames, const Font&, int width, bool multipleFilesAllowed) const; + virtual String fileListNameForWidth(const FileList*, const Font&, int width, bool multipleFilesAllowed) const; protected: // The platform selection color. @@ -234,68 +241,68 @@ protected: #if !USE(NEW_THEME) // Methods for each appearance value. - virtual void adjustCheckboxStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustCheckboxStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintCheckbox(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual void setCheckboxSize(RenderStyle*) const { } - virtual void adjustRadioStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustRadioStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintRadio(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual void setRadioSize(RenderStyle*) const { } - virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual void setButtonSize(RenderStyle*) const { } - virtual void adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } #endif - virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } #if ENABLE(METER_TAG) - virtual void adjustMeterStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustMeterStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMeter(RenderObject*, const PaintInfo&, const IntRect&); #endif #if ENABLE(PROGRESS_TAG) - virtual void adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&) { return true; } #endif #if ENABLE(INPUT_SPEECH) - virtual void adjustInputFieldSpeechButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustInputFieldSpeechButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintInputFieldSpeechButton(RenderObject*, const PaintInfo&, const IntRect&); #endif - virtual void adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSliderTrackStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSliderThumbStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&) { return true; } - virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&) { return true; } diff --git a/Source/WebCore/rendering/RenderThemeChromiumAndroid.cpp b/Source/WebCore/rendering/RenderThemeChromiumAndroid.cpp index 949fdfb5d..8b7123088 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumAndroid.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumAndroid.cpp @@ -75,7 +75,7 @@ String RenderThemeChromiumAndroid::extraDefaultStyleSheet() String(themeChromiumAndroidUserAgentStyleSheet, sizeof(themeChromiumAndroidUserAgentStyleSheet)); } -void RenderThemeChromiumAndroid::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeChromiumAndroid::adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { if (PlatformSupport::layoutTestMode()) { // Match Chromium Linux spin button style in layout tests. @@ -90,7 +90,7 @@ void RenderThemeChromiumAndroid::adjustInnerSpinButtonStyle(CSSStyleSelector*, R bool RenderThemeChromiumAndroid::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) { #if ENABLE(VIDEO) - return RenderMediaControlsChromium::paintMediaControlsPart(MediaFullscreenButton, object, paintInfo, rect); + return RenderMediaControlsChromium::paintMediaControlsPart(MediaEnterFullscreenButton, object, paintInfo, rect); #else UNUSED_PARAM(object); UNUSED_PARAM(paintInfo); diff --git a/Source/WebCore/rendering/RenderThemeChromiumAndroid.h b/Source/WebCore/rendering/RenderThemeChromiumAndroid.h index 53490135c..3dcd6df93 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumAndroid.h +++ b/Source/WebCore/rendering/RenderThemeChromiumAndroid.h @@ -37,7 +37,7 @@ public: virtual Color systemColor(int cssValidId) const OVERRIDE; - virtual void adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const OVERRIDE; + virtual void adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const OVERRIDE; virtual bool delegatesMenuListRendering() const OVERRIDE { return true; } diff --git a/Source/WebCore/rendering/RenderThemeChromiumCommon.cpp b/Source/WebCore/rendering/RenderThemeChromiumCommon.cpp new file mode 100644 index 000000000..c2b747306 --- /dev/null +++ b/Source/WebCore/rendering/RenderThemeChromiumCommon.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderThemeChromiumCommon.h" + +#include "InputType.h" + +namespace WebCore { + +bool RenderThemeChromiumCommon::supportsDataListUI(const AtomicString& type) +{ + // FIXME: We still need to support email, datetime, date, month, week, time, datetime-local, range, color. + return type == InputTypeNames::text() || type == InputTypeNames::search() || type == InputTypeNames::url() + || type == InputTypeNames::telephone() || type == InputTypeNames::number(); +} + +} diff --git a/Source/WebCore/rendering/RenderThemeChromiumCommon.h b/Source/WebCore/rendering/RenderThemeChromiumCommon.h new file mode 100644 index 000000000..be099a8e2 --- /dev/null +++ b/Source/WebCore/rendering/RenderThemeChromiumCommon.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef RenderThemeChromiumCommon_h +#define RenderThemeChromiumCommon_h + +#include <wtf/text/AtomicString.h> + +namespace WebCore { + +class RenderThemeChromiumCommon { +public: + static bool supportsDataListUI(const AtomicString& type); +}; + +} + +#endif // RenderThemeChromiumCommon_h diff --git a/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp b/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp index d4ed2a1e7..019694f0d 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumLinux.cpp @@ -305,7 +305,7 @@ bool RenderThemeChromiumLinux::paintSliderThumb(RenderObject* o, const PaintInfo return false; } -void RenderThemeChromiumLinux::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeChromiumLinux::adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize size = PlatformSupport::getThemePartSize(PlatformSupport::PartInnerSpinButton); diff --git a/Source/WebCore/rendering/RenderThemeChromiumLinux.h b/Source/WebCore/rendering/RenderThemeChromiumLinux.h index 33b6f5425..7e308083f 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumLinux.h +++ b/Source/WebCore/rendering/RenderThemeChromiumLinux.h @@ -71,7 +71,7 @@ namespace WebCore { virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool popsMenuBySpaceOrReturn() const OVERRIDE { return true; } diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.h b/Source/WebCore/rendering/RenderThemeChromiumMac.h index 232e0f66c..2b4c8c635 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumMac.h +++ b/Source/WebCore/rendering/RenderThemeChromiumMac.h @@ -24,6 +24,7 @@ #ifndef RenderThemeChromiumMac_h #define RenderThemeChromiumMac_h +#import "RenderThemeChromiumCommon.h" #import "RenderThemeMac.h" namespace WebCore { @@ -32,6 +33,8 @@ class RenderThemeChromiumMac : public RenderThemeMac { public: static PassRefPtr<RenderTheme> create(); + virtual bool supportsDataListUI(const AtomicString& type) const OVERRIDE; + protected: virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&); #if ENABLE(VIDEO) @@ -49,7 +52,7 @@ protected: 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 LayoutPoint volumeSliderOffsetFromMuteButton(RenderBox*, const LayoutSize&) const; + virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const OVERRIDE; virtual bool usesMediaControlStatusDisplay() { return false; } virtual bool hasOwnDisabledStateHandlingFor(ControlPart) const { return true; } #endif @@ -64,6 +67,9 @@ private: virtual Color disabledTextColor(const Color& textColor, const Color&) const OVERRIDE { return textColor; } virtual void updateActiveState(NSCell*, const RenderObject*); virtual String extraDefaultStyleSheet(); +#if ENABLE(CALENDAR_PICKER) + virtual CString extraCalendarPickerStyleSheet() OVERRIDE; +#endif virtual bool shouldShowPlaceholderWhenFocused() const OVERRIDE; }; diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.mm b/Source/WebCore/rendering/RenderThemeChromiumMac.mm index 82f2de1c3..a778228c5 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumMac.mm +++ b/Source/WebCore/rendering/RenderThemeChromiumMac.mm @@ -19,6 +19,8 @@ */ #import "config.h" + +#import "CalendarPickerMac.h" #import "LocalCurrentGraphicsContext.h" #import "RenderThemeChromiumMac.h" #import "PaintInfo.h" @@ -71,6 +73,11 @@ PassRefPtr<RenderTheme> RenderThemeChromiumMac::create() return adoptRef(new RenderThemeChromiumMac); } +bool RenderThemeChromiumMac::supportsDataListUI(const AtomicString& type) const +{ + return RenderThemeChromiumCommon::supportsDataListUI(type); +} + bool RenderThemeChromiumMac::usesTestModeFocusRingColor() const { return PlatformSupport::layoutTestMode(); @@ -190,6 +197,12 @@ String RenderThemeChromiumMac::extraDefaultStyleSheet() String(themeChromiumUserAgentStyleSheet, sizeof(themeChromiumUserAgentStyleSheet)); } +#if ENABLE(CALENDAR_PICKER) +CString RenderThemeChromiumMac::extraCalendarPickerStyleSheet() +{ + return CString(calendarPickerMacCss, WTF_ARRAY_LENGTH(calendarPickerMacCss)); +} +#endif bool RenderThemeChromiumMac::paintMediaVolumeSliderContainer(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) { @@ -211,7 +224,7 @@ bool RenderThemeChromiumMac::paintMediaSliderThumb(RenderObject* object, const P return RenderMediaControlsChromium::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect); } -LayoutPoint RenderThemeChromiumMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const LayoutSize& size) const +IntPoint RenderThemeChromiumMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const { return RenderTheme::volumeSliderOffsetFromMuteButton(muteButtonBox, size); } diff --git a/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp b/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp index 5715b6684..902dad013 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp @@ -25,7 +25,6 @@ #include "RenderThemeChromiumSkia.h" #include "CSSValueKeywords.h" -#include "CurrentTime.h" #include "GraphicsContext.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" @@ -44,6 +43,8 @@ #include "TransformationMatrix.h" #include "UserAgentStyleSheets.h" +#include <wtf/CurrentTime.h> + #include "SkShader.h" #include "SkGradientShader.h" @@ -124,6 +125,11 @@ bool RenderThemeChromiumSkia::supportsFocusRing(const RenderStyle* style) const return false; } +bool RenderThemeChromiumSkia::supportsDataListUI(const AtomicString& type) const +{ + return RenderThemeChromiumCommon::supportsDataListUI(type); +} + Color RenderThemeChromiumSkia::platformActiveSelectionBackgroundColor() const { return Color(0x1e, 0x90, 0xff); @@ -227,7 +233,7 @@ void RenderThemeChromiumSkia::setRadioSize(RenderStyle* style) const setCheckboxSize(style); } -void RenderThemeChromiumSkia::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeChromiumSkia::adjustButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { if (style->appearance() == PushButtonPart) { // Ignore line-height. @@ -240,7 +246,7 @@ bool RenderThemeChromiumSkia::paintTextArea(RenderObject* o, const PaintInfo& i, return paintTextField(o, i, r); } -void RenderThemeChromiumSkia::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeChromiumSkia::adjustSearchFieldStyle(StyleResolver*, RenderStyle* style, Element*) const { // Ignore line-height. style->setLineHeight(RenderStyle::initialLineHeight()); @@ -251,7 +257,7 @@ bool RenderThemeChromiumSkia::paintSearchField(RenderObject* o, const PaintInfo& return paintTextField(o, i, r); } -void RenderThemeChromiumSkia::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeChromiumSkia::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { // Scale the button size based on the font size float fontScale = style->fontSize() / defaultControlFontPixelSize; @@ -260,16 +266,16 @@ void RenderThemeChromiumSkia::adjustSearchFieldCancelButtonStyle(CSSStyleSelecto style->setHeight(Length(cancelButtonSize, Fixed)); } -LayoutRect RenderThemeChromiumSkia::convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, LayoutRect partRect, const IntRect& localOffset) const +IntRect RenderThemeChromiumSkia::convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, LayoutRect partRect, const IntRect& localOffset) const { // Compute an offset between the part renderer and the input renderer. - LayoutSize offsetFromInputRenderer = -(partRenderer->offsetFromAncestorContainer(inputRenderer)); + LayoutSize offsetFromInputRenderer = -partRenderer->offsetFromAncestorContainer(inputRenderer); // Move the rect into partRenderer's coords. partRect.move(offsetFromInputRenderer); // Account for the local drawing offset. partRect.move(localOffset.x(), localOffset.y()); - return partRect; + return pixelSnappedIntRect(partRect); } bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* cancelButtonObject, const PaintInfo& paintInfo, const IntRect& r) @@ -289,7 +295,7 @@ bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* cancelB LayoutRect cancelButtonRect(cancelButtonObject->offsetFromAncestorContainer(inputRenderBox).width(), inputContentBox.y() + (inputContentBox.height() - cancelButtonSize + 1) / 2, cancelButtonSize, cancelButtonSize); - LayoutRect paintingRect = convertToPaintingRect(inputRenderBox, cancelButtonObject, cancelButtonRect, r); + IntRect paintingRect = convertToPaintingRect(inputRenderBox, cancelButtonObject, cancelButtonRect, r); static Image* cancelImage = Image::loadPlatformResource("searchCancel").leakRef(); static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").leakRef(); @@ -298,14 +304,14 @@ bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* cancelB return false; } -void RenderThemeChromiumSkia::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeChromiumSkia::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize emptySize(1, 11); style->setWidth(Length(emptySize.width(), Fixed)); style->setHeight(Length(emptySize.height(), Fixed)); } -void RenderThemeChromiumSkia::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeChromiumSkia::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const { // Scale the decoration size based on the font size float fontScale = style->fontSize() / defaultControlFontPixelSize; @@ -332,14 +338,14 @@ bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* ma LayoutRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(), inputContentBox.y() + (inputContentBox.height() - magnifierSize + 1) / 2, magnifierSize, magnifierSize); - LayoutRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r); + IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r); static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").leakRef(); paintInfo.context->drawImage(magnifierImage, magnifierObject->style()->colorSpace(), paintingRect); return false; } -void RenderThemeChromiumSkia::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeChromiumSkia::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { // Scale the button size based on the font size float fontScale = style->fontSize() / defaultControlFontPixelSize; @@ -365,7 +371,7 @@ bool RenderThemeChromiumSkia::paintSearchFieldResultsButton(RenderObject* magnif LayoutRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(), inputContentBox.y() + (inputContentBox.height() - magnifierHeight + 1) / 2, magnifierWidth, magnifierHeight); - LayoutRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r); + IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r); static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").leakRef(); paintInfo.context->drawImage(magnifierImage, magnifierObject->style()->colorSpace(), paintingRect); @@ -465,15 +471,15 @@ bool RenderThemeChromiumSkia::paintMediaMuteButton(RenderObject* object, const P #endif } -void RenderThemeChromiumSkia::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const +void RenderThemeChromiumSkia::adjustMenuListStyle(StyleResolver*, RenderStyle* style, WebCore::Element*) const { // Height is locked to auto on all browsers. style->setLineHeight(RenderStyle::initialLineHeight()); } -void RenderThemeChromiumSkia::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeChromiumSkia::adjustMenuListButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { - adjustMenuListStyle(selector, style, e); + adjustMenuListStyle(styleResolver, style, e); } // Used to paint styled menulists (i.e. with a non-default border) diff --git a/Source/WebCore/rendering/RenderThemeChromiumSkia.h b/Source/WebCore/rendering/RenderThemeChromiumSkia.h index 05b48be3b..c5306c12f 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumSkia.h +++ b/Source/WebCore/rendering/RenderThemeChromiumSkia.h @@ -29,6 +29,7 @@ #define RenderThemeChromiumSkia_h #include "RenderTheme.h" +#include "RenderThemeChromiumCommon.h" namespace WebCore { @@ -51,6 +52,8 @@ class RenderThemeChromiumSkia : public RenderTheme { // A method asking if the theme is able to draw the focus ring. virtual bool supportsFocusRing(const RenderStyle*) const; + virtual bool supportsDataListUI(const AtomicString& type) const OVERRIDE; + // The platform selection color. virtual Color platformActiveSelectionBackgroundColor() const; virtual Color platformInactiveSelectionBackgroundColor() const; @@ -70,22 +73,22 @@ class RenderThemeChromiumSkia : public RenderTheme { virtual void setRadioSize(RenderStyle*) const; - virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaControlsBackground(RenderObject*, const PaintInfo&, const IntRect&); @@ -106,8 +109,8 @@ class RenderThemeChromiumSkia : public RenderTheme { // In short, we either go down the MenuList code path or the MenuListButton // codepath. We never go down both. And in both cases, they render the // entire menulist. - virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; - virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const; + virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); #if ENABLE(PROGRESS_TAG) @@ -157,7 +160,7 @@ private: int menuListInternalPadding(RenderStyle*, int paddingType) const; bool paintMediaButtonInternal(GraphicsContext*, const IntRect&, Image*); - LayoutRect convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, LayoutRect partRect, const IntRect& localOffset) const; + IntRect convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, LayoutRect partRect, const IntRect& localOffset) const; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp b/Source/WebCore/rendering/RenderThemeChromiumWin.cpp index 4224554ea..444212fd0 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumWin.cpp @@ -30,7 +30,6 @@ #include <vssym32.h> #include "CSSValueKeywords.h" -#include "CurrentTime.h" #include "FontSelector.h" #include "FontUtilsChromiumWin.h" #include "GraphicsContext.h" @@ -46,6 +45,8 @@ #include "ScrollbarTheme.h" #include "SystemInfo.h" #include "TransparencyWin.h" +#include <wtf/CurrentTime.h> + // FIXME: This dependency should eventually be removed. #include <skia/ext/skia_utils_win.h> @@ -101,18 +102,11 @@ public: private: - static bool canvasHasMultipleLayers(const SkCanvas* canvas) - { - SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false); - iter.next(); // There is always at least one layer. - return !iter.done(); // There is > 1 layer if the the iterator can stil advance. - } - static TransparencyWin::LayerMode getLayerMode(GraphicsContext* context, TransparencyWin::TransformMode transformMode) { if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background. return TransparencyWin::WhiteLayer; - if (canvasHasMultipleLayers(context->platformContext()->canvas())) // Needs antialiasing help. + if (context->platformContext()->canvas()->isDrawingToLayer()) // Needs antialiasing help. return TransparencyWin::OpaqueCompositeLayer; // Nothing interesting. return transformMode == TransparencyWin::KeepTransform ? TransparencyWin::NoLayer : TransparencyWin::OpaqueCompositeLayer; @@ -143,7 +137,7 @@ bool ThemePainter::s_hasInstance = false; static void getNonClientMetrics(NONCLIENTMETRICS* metrics) { static UINT size = (windowsVersion() >= WindowsVista) ? - (sizeof NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; + sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; metrics->cbSize = size; bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0); ASSERT(success); @@ -712,7 +706,7 @@ bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o, return false; } -void RenderThemeChromiumWin::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeChromiumWin::adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { int width = ScrollbarTheme::theme()->scrollbarThickness(); style->setWidth(Length(width, Fixed)); @@ -766,7 +760,7 @@ double RenderThemeChromiumWin::animationDurationForProgressBar(RenderProgress* r return progressAnimationFrameRate; } -void RenderThemeChromiumWin::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderThemeChromiumWin::adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const { } diff --git a/Source/WebCore/rendering/RenderThemeChromiumWin.h b/Source/WebCore/rendering/RenderThemeChromiumWin.h index c47a67910..7856d039f 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumWin.h +++ b/Source/WebCore/rendering/RenderThemeChromiumWin.h @@ -86,13 +86,13 @@ namespace WebCore { // See comment in RenderThemeChromiumSkia::setDefaultFontSize() regarding ugliness of this hack. static void setDefaultFontSize(int); - virtual void adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&); #if ENABLE(PROGRESS_TAG) virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const; virtual double animationDurationForProgressBar(RenderProgress*) const; - virtual void adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&); #endif diff --git a/Source/WebCore/rendering/RenderThemeMac.h b/Source/WebCore/rendering/RenderThemeMac.h index f8a5657ae..ebbb2352c 100644 --- a/Source/WebCore/rendering/RenderThemeMac.h +++ b/Source/WebCore/rendering/RenderThemeMac.h @@ -45,7 +45,7 @@ public: // A general method asking if any control tinting is supported at all. virtual bool supportsControlTints() const { return true; } - virtual void adjustRepaintRect(const RenderObject*, LayoutRect&); + virtual void adjustRepaintRect(const RenderObject*, IntRect&) OVERRIDE; virtual bool isControlStyled(const RenderStyle*, const BorderData&, const FillLayer&, const Color& backgroundColor) const; @@ -74,12 +74,12 @@ public: virtual int popupInternalPaddingTop(RenderStyle*) const; virtual int popupInternalPaddingBottom(RenderStyle*) const; - virtual bool paintCapsLockIndicator(RenderObject*, const PaintInfo&, const LayoutRect&); + virtual bool paintCapsLockIndicator(RenderObject*, const PaintInfo&, const IntRect&) OVERRIDE; virtual bool popsMenuByArrowKeys() const OVERRIDE { return true; } #if ENABLE(METER_TAG) - virtual LayoutSize meterSizeForBounds(const RenderMeter*, const LayoutRect&) const; + virtual IntSize meterSizeForBounds(const RenderMeter*, const IntRect&) const OVERRIDE; virtual bool paintMeter(RenderObject*, const PaintInfo&, const IntRect&); virtual bool supportsMeter(ControlPart) const; #endif @@ -103,41 +103,41 @@ protected: virtual bool supportsSelectionForegroundColors() const { return false; } virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const; #if ENABLE(PROGRESS_TAG) - virtual void adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&); #endif virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSliderTrackStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSliderThumbStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&); #if ENABLE(VIDEO) @@ -171,26 +171,26 @@ protected: virtual bool usesMediaControlStatusDisplay(); virtual bool usesMediaControlVolumeSlider() const; virtual void adjustMediaSliderThumbSize(RenderStyle*) const; - virtual LayoutPoint volumeSliderOffsetFromMuteButton(RenderBox*, const LayoutSize&) const; + virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const OVERRIDE; #endif virtual bool shouldShowPlaceholderWhenFocused() const; private: - virtual String fileListNameForWidth(const Vector<String>& filenames, const Font&, int width, bool multipleFilesAllowed) const; + virtual String fileListNameForWidth(const FileList*, const Font&, int width, bool multipleFilesAllowed) const OVERRIDE; - LayoutRect inflateRect(const LayoutRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const; + IntRect inflateRect(const IntRect&, const IntSize&, const int* margins, float zoomLevel = 1.0f) const; FloatRect convertToPaintingRect(const RenderObject* inputRenderer, const RenderObject* partRenderer, const FloatRect& inputRect, const IntRect& r) const; // Get the control size based off the font. Used by some of the controls (like buttons). NSControlSize controlSizeForFont(RenderStyle*) const; NSControlSize controlSizeForSystemFont(RenderStyle*) const; - void setControlSize(NSCell*, const IntSize* sizes, const LayoutSize& minSize, float zoomLevel = 1.0f); + void setControlSize(NSCell*, const IntSize* sizes, const IntSize& minSize, float zoomLevel = 1.0f); void setSizeFromFont(RenderStyle*, const IntSize* sizes) const; IntSize sizeForFont(RenderStyle*, const IntSize* sizes) const; IntSize sizeForSystemFont(RenderStyle*, const IntSize* sizes) const; - void setFontFromControlSize(CSSStyleSelector*, RenderStyle*, NSControlSize) const; + void setFontFromControlSize(StyleResolver*, RenderStyle*, NSControlSize) const; void updateCheckedState(NSCell*, const RenderObject*); void updateEnabledState(NSCell*, const RenderObject*); @@ -201,7 +201,7 @@ private: // Helpers for adjusting appearance and for painting - void setPopupButtonCellState(const RenderObject*, const LayoutRect&); + void setPopupButtonCellState(const RenderObject*, const IntRect&); const IntSize* popupButtonSizes() const; const int* popupButtonMargins() const; const int* popupButtonPadding(NSControlSize) const; diff --git a/Source/WebCore/rendering/RenderThemeMac.mm b/Source/WebCore/rendering/RenderThemeMac.mm index 0ae0196bc..801b235a9 100644 --- a/Source/WebCore/rendering/RenderThemeMac.mm +++ b/Source/WebCore/rendering/RenderThemeMac.mm @@ -22,10 +22,11 @@ #import "BitmapImage.h" #import "ColorMac.h" -#import "CSSStyleSelector.h" +#import "CSSValueList.h" #import "CSSValueKeywords.h" #import "Document.h" #import "Element.h" +#import "FileList.h" #import "FrameView.h" #import "GraphicsContextCG.h" #import "HTMLInputElement.h" @@ -43,6 +44,7 @@ #import "RenderView.h" #import "SharedBuffer.h" #import "StringTruncator.h" +#import "StyleResolver.h" #import "TimeRanges.h" #import "ThemeMac.h" #import "WebCoreSystemInterface.h" @@ -487,7 +489,7 @@ NSView* RenderThemeMac::documentViewFor(RenderObject* o) const bool RenderThemeMac::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& background, const Color& backgroundColor) const { - if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart || style->appearance() == ListboxPart) + if (style->appearance() == TextAreaPart || style->appearance() == ListboxPart) return style->border() != border; // FIXME: This is horrible, but there is not much else that can be done. Menu lists cannot draw properly when @@ -500,7 +502,7 @@ bool RenderThemeMac::isControlStyled(const RenderStyle* style, const BorderData& return RenderTheme::isControlStyled(style, border, background, backgroundColor); } -void RenderThemeMac::adjustRepaintRect(const RenderObject* o, LayoutRect& r) +void RenderThemeMac::adjustRepaintRect(const RenderObject* o, IntRect& r) { ControlPart part = o->style()->appearance(); @@ -510,7 +512,6 @@ void RenderThemeMac::adjustRepaintRect(const RenderObject* o, LayoutRect& r) case RadioPart: case PushButtonPart: case SquareButtonPart: - case ListButtonPart: case DefaultButtonPart: case ButtonPart: case InnerSpinButtonPart: @@ -531,13 +532,13 @@ void RenderThemeMac::adjustRepaintRect(const RenderObject* o, LayoutRect& r) } } -LayoutRect RenderThemeMac::inflateRect(const LayoutRect& r, const IntSize& size, const int* margins, float zoomLevel) const +IntRect RenderThemeMac::inflateRect(const IntRect& r, const IntSize& size, const int* margins, float zoomLevel) const { // Only do the inflation if the available width/height are too small. Otherwise try to // fit the glow/check space into the available box's width/height. - LayoutUnit widthDelta = r.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel); - LayoutUnit heightDelta = r.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel); - LayoutRect result(r); + int widthDelta = r.width() - (size.width() + margins[leftMargin] * zoomLevel + margins[rightMargin] * zoomLevel); + int heightDelta = r.height() - (size.height() + margins[topMargin] * zoomLevel + margins[bottomMargin] * zoomLevel); + IntRect result(r); if (widthDelta < 0) { result.setX(result.x() - margins[leftMargin] * zoomLevel); result.setWidth(result.width() - widthDelta); @@ -558,7 +559,7 @@ FloatRect RenderThemeMac::convertToPaintingRect(const RenderObject* inputRendere const RenderObject* renderer = partRenderer; while (renderer && renderer != inputRenderer) { RenderObject* containingRenderer = renderer->container(); - offsetFromInputRenderer -= renderer->offsetFromContainer(containingRenderer, LayoutPoint()); + offsetFromInputRenderer -= roundedIntSize(renderer->offsetFromContainer(containingRenderer, LayoutPoint())); renderer = containingRenderer; } // If the input renderer was not a container, something went wrong @@ -639,14 +640,14 @@ NSControlSize RenderThemeMac::controlSizeForFont(RenderStyle* style) const return NSMiniControlSize; } -void RenderThemeMac::setControlSize(NSCell* cell, const IntSize* sizes, const LayoutSize& minSize, float zoomLevel) +void RenderThemeMac::setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minSize, float zoomLevel) { NSControlSize size; - if (minSize.width() >= static_cast<LayoutUnit>(sizes[NSRegularControlSize].width() * zoomLevel) && - minSize.height() >= static_cast<LayoutUnit>(sizes[NSRegularControlSize].height() * zoomLevel)) + if (minSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomLevel) && + minSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomLevel)) size = NSRegularControlSize; - else if (minSize.width() >= static_cast<LayoutUnit>(sizes[NSSmallControlSize].width() * zoomLevel) && - minSize.height() >= static_cast<LayoutUnit>(sizes[NSSmallControlSize].height() * zoomLevel)) + else if (minSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomLevel) && + minSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomLevel)) size = NSSmallControlSize; else size = NSMiniControlSize; @@ -682,7 +683,7 @@ void RenderThemeMac::setSizeFromFont(RenderStyle* style, const IntSize* sizes) c style->setHeight(Length(size.height(), Fixed)); } -void RenderThemeMac::setFontFromControlSize(CSSStyleSelector*, RenderStyle* style, NSControlSize controlSize) const +void RenderThemeMac::setFontFromControlSize(StyleResolver*, RenderStyle* style, NSControlSize controlSize) const { FontDescription fontDescription; fontDescription.setIsAbsoluteSize(true); @@ -725,11 +726,11 @@ bool RenderThemeMac::paintTextField(RenderObject* o, const PaintInfo& paintInfo, return false; } -void RenderThemeMac::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderThemeMac::adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const { } -bool RenderThemeMac::paintCapsLockIndicator(RenderObject*, const PaintInfo& paintInfo, const LayoutRect& r) +bool RenderThemeMac::paintCapsLockIndicator(RenderObject*, const PaintInfo& paintInfo, const IntRect& r) { if (paintInfo.context->paintingDisabled()) return true; @@ -747,7 +748,7 @@ bool RenderThemeMac::paintTextArea(RenderObject* o, const PaintInfo& paintInfo, return false; } -void RenderThemeMac::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderThemeMac::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const { } @@ -792,7 +793,7 @@ bool RenderThemeMac::paintMenuList(RenderObject* o, const PaintInfo& paintInfo, size.setWidth(r.width()); // Now inflate it to account for the shadow. - LayoutRect inflatedRect = r; + IntRect inflatedRect = r; if (r.width() >= minimumMenuListSize(o->style())) inflatedRect = inflateRect(inflatedRect, size, popupButtonMargins(), zoomLevel); @@ -817,16 +818,16 @@ bool RenderThemeMac::paintMenuList(RenderObject* o, const PaintInfo& paintInfo, #if ENABLE(METER_TAG) -LayoutSize RenderThemeMac::meterSizeForBounds(const RenderMeter* renderMeter, const LayoutRect& bounds) const +IntSize RenderThemeMac::meterSizeForBounds(const RenderMeter* renderMeter, const IntRect& bounds) const { if (NoControlPart == renderMeter->style()->appearance()) return bounds.size(); NSLevelIndicatorCell* cell = levelIndicatorFor(renderMeter); // Makes enough room for cell's intrinsic size. - NSSize cellSize = [cell cellSizeForBounds:LayoutRect(LayoutPoint(), bounds.size())]; - return LayoutSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(), - bounds.height() < cellSize.height ? cellSize.height : bounds.height()); + NSSize cellSize = [cell cellSizeForBounds:IntRect(IntPoint(), bounds.size())]; + return IntSize(bounds.width() < cellSize.width ? cellSize.width : bounds.width(), + bounds.height() < cellSize.height ? cellSize.height : bounds.height()); } bool RenderThemeMac::paintMeter(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) @@ -952,7 +953,7 @@ double RenderThemeMac::animationDurationForProgressBar(RenderProgress*) const return progressAnimationNumFrames * progressAnimationFrameRate; } -void RenderThemeMac::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderThemeMac::adjustProgressBarStyle(StyleResolver*, RenderStyle*, Element*) const { } @@ -1072,7 +1073,7 @@ void RenderThemeMac::paintMenuListButtonGradients(RenderObject* o, const PaintIn GraphicsContextStateSaver stateSaver(*paintInfo.context); - RoundedRect border = o->style()->getRoundedBorderFor(r); + RoundedRect border = o->style()->getRoundedBorderFor(r, o->view()); int radius = border.radii().topLeft().width(); CGColorSpaceRef cspace = deviceRGBColorSpaceRef(); @@ -1196,7 +1197,7 @@ static const IntSize* menuListButtonSizes() return sizes; } -void RenderThemeMac::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeMac::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { NSControlSize controlSize = controlSizeForFont(style); @@ -1219,7 +1220,7 @@ void RenderThemeMac::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate // system font for the control size instead. - setFontFromControlSize(selector, style, controlSize); + setFontFromControlSize(styleResolver, style, controlSize); style->setBoxShadow(nullptr); } @@ -1263,7 +1264,7 @@ int RenderThemeMac::popupInternalPaddingBottom(RenderStyle* style) const return 0; } -void RenderThemeMac::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeMac::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { float fontScale = style->fontSize() / baseFontSize; @@ -1276,7 +1277,7 @@ void RenderThemeMac::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* s style->setLineHeight(RenderStyle::initialLineHeight()); } -void RenderThemeMac::setPopupButtonCellState(const RenderObject* o, const LayoutRect& r) +void RenderThemeMac::setPopupButtonCellState(const RenderObject* o, const IntRect& r) { NSPopUpButtonCell* popupButton = this->popupButton(); @@ -1305,7 +1306,7 @@ int RenderThemeMac::minimumMenuListSize(RenderStyle* style) const const int trackWidth = 5; const int trackRadius = 2; -void RenderThemeMac::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeMac::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const { style->setBoxShadow(nullptr); } @@ -1347,9 +1348,9 @@ bool RenderThemeMac::paintSliderTrack(RenderObject* o, const PaintInfo& paintInf return false; } -void RenderThemeMac::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const +void RenderThemeMac::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const { - RenderTheme::adjustSliderThumbStyle(selector, style, element); + RenderTheme::adjustSliderThumbStyle(styleResolver, style, element); style->setBoxShadow(nullptr); } @@ -1478,7 +1479,7 @@ void RenderThemeMac::setSearchFieldSize(RenderStyle* style) const setSizeFromFont(style, searchFieldSizes()); } -void RenderThemeMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element*) const +void RenderThemeMac::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element*) const { // Override border. style->resetBorder(); @@ -1504,7 +1505,7 @@ void RenderThemeMac::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderSt style->setPaddingBottom(Length(padding, Fixed)); NSControlSize controlSize = controlSizeForFont(style); - setFontFromControlSize(selector, style, controlSize); + setFontFromControlSize(styleResolver, style, controlSize); style->setBoxShadow(nullptr); } @@ -1533,14 +1534,14 @@ bool RenderThemeMac::paintSearchFieldCancelButton(RenderObject* o, const PaintIn float zoomLevel = o->style()->effectiveZoom(); - FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())]; + FloatRect localBounds = [search cancelButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())]; #if ENABLE(INPUT_SPEECH) // Take care of cases where the cancel button was not aligned with the right border of the input element (for e.g. // when speech input is enabled for the input element. - LayoutRect absBoundingBox = input->renderer()->absoluteBoundingBoxRect(); - LayoutUnit absRight = absBoundingBox.x() + absBoundingBox.width() - input->renderBox()->paddingRight() - input->renderBox()->borderRight(); - LayoutUnit spaceToRightOfCancelButton = absRight - (r.x() + r.width()); + IntRect absBoundingBox = input->renderer()->absoluteBoundingBoxRect(); + int absRight = absBoundingBox.x() + absBoundingBox.width() - input->renderBox()->paddingRight() - input->renderBox()->borderRight(); + int spaceToRightOfCancelButton = absRight - (r.x() + r.width()); localBounds.setX(localBounds.x() - spaceToRightOfCancelButton); #endif @@ -1566,7 +1567,7 @@ const IntSize* RenderThemeMac::cancelButtonSizes() const return sizes; } -void RenderThemeMac::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeMac::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, cancelButtonSizes()); style->setWidth(Length(size.width(), Fixed)); @@ -1581,7 +1582,7 @@ const IntSize* RenderThemeMac::resultsButtonSizes() const } const int emptyResultsOffset = 9; -void RenderThemeMac::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeMac::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, resultsButtonSizes()); style->setWidth(Length(size.width() - emptyResultsOffset, Fixed)); @@ -1594,7 +1595,7 @@ bool RenderThemeMac::paintSearchFieldDecoration(RenderObject*, const PaintInfo&, return false; } -void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeMac::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, resultsButtonSizes()); style->setWidth(Length(size.width(), Fixed)); @@ -1618,7 +1619,7 @@ bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const Pa updateActiveState([search searchButtonCell], o); - FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())]; + FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())]; localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); [[search searchButtonCell] drawWithFrame:localBounds inView:documentViewFor(o)]; @@ -1627,7 +1628,7 @@ bool RenderThemeMac::paintSearchFieldResultsDecoration(RenderObject* o, const Pa } const int resultsArrowWidth = 5; -void RenderThemeMac::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeMac::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, resultsButtonSizes()); style->setWidth(Length(size.width() + resultsArrowWidth, Fixed)); @@ -1654,7 +1655,7 @@ bool RenderThemeMac::paintSearchFieldResultsButton(RenderObject* o, const PaintI GraphicsContextStateSaver stateSaver(*paintInfo.context); float zoomLevel = o->style()->effectiveZoom(); - FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->borderBoxRect())]; + FloatRect localBounds = [search searchButtonRectForBounds:NSRect(input->renderBox()->pixelSnappedBorderBoxRect())]; localBounds = convertToPaintingRect(input->renderer(), o, localBounds, r); IntRect unzoomedRect(localBounds); @@ -1789,8 +1790,10 @@ bool RenderThemeMac::paintMediaFullscreenButton(RenderObject* o, const PaintInfo if (!node) return false; - LocalCurrentGraphicsContext localContext(paintInfo.context); - wkDrawMediaUIPart(MediaFullscreenButton, mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node)); + if (MediaControlFullscreenButtonElement* btn = static_cast<MediaControlFullscreenButtonElement*>(o->node())) { + LocalCurrentGraphicsContext localContext(paintInfo.context); + wkDrawMediaUIPart(btn->displayType(), mediaControllerTheme(), localContext.cgContext(), r, getMediaUIPartStateFlags(node)); + } return false; } @@ -2056,7 +2059,7 @@ bool RenderThemeMac::usesMediaControlVolumeSlider() const return mediaControllerTheme() == MediaControllerThemeQuickTime; } -LayoutPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const LayoutSize& size) const +IntPoint RenderThemeMac::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const { return RenderMediaControls::volumeSliderOffsetFromMuteButton(muteButtonBox, size); } @@ -2137,28 +2140,23 @@ NSTextFieldCell* RenderThemeMac::textField() const [m_textField.get() setBezeled:YES]; [m_textField.get() setEditable:YES]; [m_textField.get() setFocusRingType:NSFocusRingTypeExterior]; - - // Setting a clear background on the cell is necessary for CSS-styled backgrounds - // to show through. Ideally, there would be a better way to do this. - [m_textField.get() setDrawsBackground:YES]; - [m_textField.get() setBackgroundColor:[NSColor clearColor]]; } return m_textField.get(); } -String RenderThemeMac::fileListNameForWidth(const Vector<String>& filenames, const Font& font, int width, bool multipleFilesAllowed) const +String RenderThemeMac::fileListNameForWidth(const FileList* fileList, const Font& font, int width, bool multipleFilesAllowed) const { if (width <= 0) return String(); String strToTruncate; - if (filenames.isEmpty()) + if (fileList->isEmpty()) strToTruncate = fileListDefaultLabel(multipleFilesAllowed); - else if (filenames.size() == 1) - strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(filenames[0])]; + else if (fileList->length() == 1) + strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(fileList->item(0)->path())]; else - return StringTruncator::rightTruncate(multipleFileUploadText(filenames.size()), width, font, StringTruncator::EnableRoundingHacks); + return StringTruncator::rightTruncate(multipleFileUploadText(fileList->length()), width, font, StringTruncator::EnableRoundingHacks); return StringTruncator::centerTruncate(strToTruncate, width, font, StringTruncator::EnableRoundingHacks); } diff --git a/Source/WebCore/rendering/RenderThemeSafari.cpp b/Source/WebCore/rendering/RenderThemeSafari.cpp index 771f19426..00a5d7e66 100644 --- a/Source/WebCore/rendering/RenderThemeSafari.cpp +++ b/Source/WebCore/rendering/RenderThemeSafari.cpp @@ -40,10 +40,10 @@ #include "RenderMediaControls.h" #include "RenderSlider.h" #include "RenderView.h" -#include "RetainPtr.h" #include "SoftLinking.h" -#include "cssstyleselector.h" +#include "StyleResolver.h" #include <CoreGraphics/CoreGraphics.h> +#include <wtf/RetainPtr.h> using std::min; @@ -383,7 +383,7 @@ void RenderThemeSafari::setSizeFromFont(RenderStyle* style, const IntSize* sizes style->setHeight(Length(size.height(), Fixed)); } -void RenderThemeSafari::setFontFromControlSize(CSSStyleSelector* selector, RenderStyle* style, NSControlSize controlSize) const +void RenderThemeSafari::setFontFromControlSize(StyleResolver* styleResolver, RenderStyle* style, NSControlSize controlSize) const { FontDescription fontDescription; fontDescription.setIsAbsoluteSize(true); @@ -398,7 +398,7 @@ void RenderThemeSafari::setFontFromControlSize(CSSStyleSelector* selector, Rende style->setLineHeight(RenderStyle::initialLineHeight()); if (style->setFontDescription(fontDescription)) - style->font().update(selector->fontSelector()); + style->font().update(styleResolver->fontSelector()); } NSControlSize RenderThemeSafari::controlSizeForSystemFont(RenderStyle* style) const @@ -503,7 +503,7 @@ void RenderThemeSafari::setButtonPaddingFromControlSize(RenderStyle* style, NSCo style->setPaddingBottom(Length(0, Fixed)); } -void RenderThemeSafari::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeSafari::adjustButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { // There are three appearance constants for buttons. // (1) Push-button is the constant for the default Aqua system button. Push buttons will not scale vertically and will not allow @@ -536,7 +536,7 @@ void RenderThemeSafari::adjustButtonStyle(CSSStyleSelector* selector, RenderStyl // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate // system font for the control size instead. - setFontFromControlSize(selector, style, controlSize); + setFontFromControlSize(styleResolver, style, controlSize); } else { // Set a min-height so that we can't get smaller than the mini button. style->setMinHeight(Length(15, Fixed)); @@ -615,7 +615,7 @@ bool RenderThemeSafari::paintTextField(RenderObject* o, const PaintInfo& paintIn return false; } -void RenderThemeSafari::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderThemeSafari::adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const { } @@ -643,7 +643,7 @@ bool RenderThemeSafari::paintTextArea(RenderObject* o, const PaintInfo& paintInf return false; } -void RenderThemeSafari::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const +void RenderThemeSafari::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const { } @@ -859,7 +859,7 @@ bool RenderThemeSafari::paintMenuListButton(RenderObject* o, const PaintInfo& pa return false; } -void RenderThemeSafari::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeSafari::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { NSControlSize controlSize = controlSizeForFont(style); @@ -882,7 +882,7 @@ void RenderThemeSafari::adjustMenuListStyle(CSSStyleSelector* selector, RenderSt // Our font is locked to the appropriate system font size for the control. To clarify, we first use the CSS-specified font to figure out // a reasonable control size, but once that control size is determined, we throw that font away and use the appropriate // system font for the control size instead. - setFontFromControlSize(selector, style, controlSize); + setFontFromControlSize(styleResolver, style, controlSize); } int RenderThemeSafari::popupInternalPaddingLeft(RenderStyle* style) const @@ -924,7 +924,7 @@ int RenderThemeSafari::popupInternalPaddingBottom(RenderStyle* style) const return 0; } -void RenderThemeSafari::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeSafari::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { float fontScale = style->fontSize() / baseFontSize; @@ -988,9 +988,9 @@ bool RenderThemeSafari::paintSliderTrack(RenderObject* o, const PaintInfo& paint return false; } -void RenderThemeSafari::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeSafari::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { - RenderTheme::adjustSliderThumbStyle(selector, style, e); + RenderTheme::adjustSliderThumbStyle(styleResolver, style, e); style->setBoxShadow(nullptr); } @@ -1042,7 +1042,7 @@ void RenderThemeSafari::setSearchFieldSize(RenderStyle* style) const setSizeFromFont(style, searchFieldSizes()); } -void RenderThemeSafari::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeSafari::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { // Override border. style->resetBorder(); @@ -1068,7 +1068,7 @@ void RenderThemeSafari::adjustSearchFieldStyle(CSSStyleSelector* selector, Rende style->setPaddingBottom(Length(padding, Fixed)); NSControlSize controlSize = controlSizeForFont(style); - setFontFromControlSize(selector, style, controlSize); + setFontFromControlSize(styleResolver, style, controlSize); } bool RenderThemeSafari::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect&) @@ -1092,7 +1092,7 @@ const IntSize* RenderThemeSafari::cancelButtonSizes() const return sizes; } -void RenderThemeSafari::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeSafari::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, cancelButtonSizes()); style->setWidth(Length(size.width(), Fixed)); @@ -1106,7 +1106,7 @@ const IntSize* RenderThemeSafari::resultsButtonSizes() const } const int emptyResultsOffset = 9; -void RenderThemeSafari::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeSafari::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, resultsButtonSizes()); style->setWidth(Length(size.width() - emptyResultsOffset, Fixed)); @@ -1118,7 +1118,7 @@ bool RenderThemeSafari::paintSearchFieldDecoration(RenderObject*, const PaintInf return false; } -void RenderThemeSafari::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeSafari::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, resultsButtonSizes()); style->setWidth(Length(size.width(), Fixed)); @@ -1141,7 +1141,7 @@ bool RenderThemeSafari::paintSearchFieldResultsDecoration(RenderObject* o, const } const int resultsArrowWidth = 5; -void RenderThemeSafari::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeSafari::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize size = sizeForSystemFont(style, resultsButtonSizes()); style->setWidth(Length(size.width() + resultsArrowWidth, Fixed)); @@ -1165,7 +1165,7 @@ bool RenderThemeSafari::paintSearchFieldResultsButton(RenderObject* o, const Pai #if ENABLE(VIDEO) bool RenderThemeSafari::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - return RenderMediaControls::paintMediaControlsPart(MediaFullscreenButton, o, paintInfo, r); + return RenderMediaControls::paintMediaControlsPart(MediaEnterFullscreenButton, o, paintInfo, r); } bool RenderThemeSafari::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) diff --git a/Source/WebCore/rendering/RenderThemeSafari.h b/Source/WebCore/rendering/RenderThemeSafari.h index 85ddb4d50..05b1fb5ea 100644 --- a/Source/WebCore/rendering/RenderThemeSafari.h +++ b/Source/WebCore/rendering/RenderThemeSafari.h @@ -77,7 +77,7 @@ public: virtual int minimumMenuListSize(RenderStyle*) const; virtual void adjustSliderThumbSize(RenderStyle*) const; - virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSliderThumbStyle(StyleResolver*, RenderStyle*, Element*) const; virtual int popupInternalPaddingLeft(RenderStyle*) const; virtual int popupInternalPaddingRight(RenderStyle*) const; @@ -92,38 +92,38 @@ protected: virtual bool paintRadio(RenderObject*, const PaintInfo&, const IntRect&); virtual void setRadioSize(RenderStyle*) const; - virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, WebCore::Element*) const; + virtual void adjustButtonStyle(StyleResolver*, RenderStyle*, WebCore::Element*) const; virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&); virtual void setButtonSize(RenderStyle*) const; virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustTextFieldStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const; - virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintCapsLockIndicator(RenderObject*, const PaintInfo&, const IntRect&); @@ -154,7 +154,7 @@ private: void setSizeFromFont(RenderStyle*, const IntSize* sizes) const; IntSize sizeForFont(RenderStyle*, const IntSize* sizes) const; IntSize sizeForSystemFont(RenderStyle*, const IntSize* sizes) const; - void setFontFromControlSize(CSSStyleSelector*, RenderStyle*, NSControlSize) const; + void setFontFromControlSize(StyleResolver*, RenderStyle*, NSControlSize) const; // Helpers for adjusting appearance and for painting const IntSize* checkboxSizes() const; diff --git a/Source/WebCore/rendering/RenderThemeWin.cpp b/Source/WebCore/rendering/RenderThemeWin.cpp index 16795c3b7..e58bad9e1 100644 --- a/Source/WebCore/rendering/RenderThemeWin.cpp +++ b/Source/WebCore/rendering/RenderThemeWin.cpp @@ -687,7 +687,7 @@ bool RenderThemeWin::paintButton(RenderObject* o, const PaintInfo& i, const IntR return false; } -void RenderThemeWin::adjustInnerSpinButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWin::adjustInnerSpinButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { int width = ::GetSystemMetrics(SM_CXVSCROLL); if (width <= 0) @@ -754,13 +754,13 @@ bool RenderThemeWin::paintMenuList(RenderObject* o, const PaintInfo& i, const In return paintMenuListButton(o, i, r); } -void RenderThemeWin::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWin::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { style->resetBorder(); - adjustMenuListButtonStyle(selector, style, e); + adjustMenuListButtonStyle(styleResolver, style, e); } -void RenderThemeWin::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWin::adjustMenuListButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { // These are the paddings needed to place the text correctly in the <select> box const int dropDownBoxPaddingTop = 2; @@ -862,7 +862,7 @@ bool RenderThemeWin::paintSearchField(RenderObject* o, const PaintInfo& i, const return paintTextField(o, i, r); } -void RenderThemeWin::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWin::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { // Override paddingSize to match AppKit text positioning. const int padding = 1; @@ -876,14 +876,14 @@ void RenderThemeWin::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderSt bool RenderThemeWin::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - LayoutRect bounds = r; + IntRect bounds = r; ASSERT(o->parent()); if (!o->parent() || !o->parent()->isBox()) return false; RenderBox* parentRenderBox = toRenderBox(o->parent()); - LayoutRect parentBox = parentRenderBox->absoluteContentBox(); + IntRect parentBox = parentRenderBox->absoluteContentBox(); // Make sure the scaled button stays square and will fit in its parent's box bounds.setHeight(min(parentBox.width(), min(parentBox.height(), bounds.height()))); @@ -899,7 +899,7 @@ bool RenderThemeWin::paintSearchFieldCancelButton(RenderObject* o, const PaintIn return false; } -void RenderThemeWin::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWin::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { // Scale the button size based on the font size float fontScale = style->fontSize() / defaultControlFontPixelSize; @@ -908,14 +908,14 @@ void RenderThemeWin::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* select style->setHeight(Length(cancelButtonSize, Fixed)); } -void RenderThemeWin::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWin::adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize emptySize(1, 11); style->setWidth(Length(emptySize.width(), Fixed)); style->setHeight(Length(emptySize.height(), Fixed)); } -void RenderThemeWin::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWin::adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle* style, Element*) const { // Scale the decoration size based on the font size float fontScale = style->fontSize() / defaultControlFontPixelSize; @@ -927,13 +927,13 @@ void RenderThemeWin::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* s bool RenderThemeWin::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - LayoutRect bounds = r; + IntRect bounds = r; ASSERT(o->parent()); if (!o->parent() || !o->parent()->isBox()) return false; RenderBox* parentRenderBox = toRenderBox(o->parent()); - LayoutRect parentBox = parentRenderBox->absoluteContentBox(); + IntRect parentBox = parentRenderBox->absoluteContentBox(); // Make sure the scaled decoration stays square and will fit in its parent's box bounds.setHeight(min(parentBox.width(), min(parentBox.height(), bounds.height()))); @@ -948,7 +948,7 @@ bool RenderThemeWin::paintSearchFieldResultsDecoration(RenderObject* o, const Pa return false; } -void RenderThemeWin::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWin::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { // Scale the button size based on the font size float fontScale = style->fontSize() / defaultControlFontPixelSize; @@ -961,7 +961,7 @@ void RenderThemeWin::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selec bool RenderThemeWin::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - LayoutRect bounds = r; + IntRect bounds = r; ASSERT(o->parent()); if (!o->parent()) return false; @@ -969,11 +969,11 @@ bool RenderThemeWin::paintSearchFieldResultsButton(RenderObject* o, const PaintI return false; RenderBox* parentRenderBox = toRenderBox(o->parent()); - LayoutRect parentBox = parentRenderBox->absoluteContentBox(); + IntRect parentBox = parentRenderBox->absoluteContentBox(); // Make sure the scaled decoration will fit in its parent's box bounds.setHeight(min(parentBox.height(), bounds.height())); - bounds.setWidth(min<LayoutUnit>(parentBox.width(), bounds.height() * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize)); + bounds.setWidth(min<int>(parentBox.width(), bounds.height() * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize)); // Center the button vertically. Round up though, so if it has to be one pixel off-center, it will // be one pixel closer to the bottom of the field. This tends to look better with the text. @@ -1056,7 +1056,7 @@ bool RenderThemeWin::supportsClosedCaptioning() const bool RenderThemeWin::paintMediaFullscreenButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { - return RenderMediaControls::paintMediaControlsPart(MediaFullscreenButton, o, paintInfo, r); + return RenderMediaControls::paintMediaControlsPart(MediaEnterFullscreenButton, o, paintInfo, r); } bool RenderThemeWin::paintMediaMuteButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) @@ -1119,7 +1119,7 @@ bool RenderThemeWin::paintMediaVolumeSliderThumb(RenderObject* o, const PaintInf return RenderMediaControls::paintMediaControlsPart(MediaVolumeSliderThumb, o, paintInfo, r); } -LayoutPoint RenderThemeWin::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const LayoutSize& size) const +IntPoint RenderThemeWin::volumeSliderOffsetFromMuteButton(RenderBox* muteButtonBox, const IntSize& size) const { return RenderMediaControls::volumeSliderOffsetFromMuteButton(muteButtonBox, size); } diff --git a/Source/WebCore/rendering/RenderThemeWin.h b/Source/WebCore/rendering/RenderThemeWin.h index 293796c90..d2337c361 100644 --- a/Source/WebCore/rendering/RenderThemeWin.h +++ b/Source/WebCore/rendering/RenderThemeWin.h @@ -77,7 +77,7 @@ public: virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustInnerSpinButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintInnerSpinButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&); @@ -85,9 +85,9 @@ public: virtual bool paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r) { return paintTextField(o, i, r); } - virtual void adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const; + virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const; + virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); @@ -97,26 +97,26 @@ public: virtual bool popupOptionSupportsTextIndent() const { return true; } - virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&) { return false; } - virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&); virtual void themeChanged(); - virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {} - virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {} - virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {} + virtual void adjustButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { } + virtual void adjustTextFieldStyle(StyleResolver*, RenderStyle* style, Element*) const { } + virtual void adjustTextAreaStyle(StyleResolver*, RenderStyle* style, Element*) const { } static void setWebKitIsBeingUnloaded(); @@ -141,7 +141,7 @@ public: 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 LayoutPoint volumeSliderOffsetFromMuteButton(RenderBox*, const LayoutSize&) const; + virtual IntPoint volumeSliderOffsetFromMuteButton(RenderBox*, const IntSize&) const OVERRIDE; #endif virtual bool shouldShowPlaceholderWhenFocused() const { return true; } diff --git a/Source/WebCore/rendering/RenderThemeWinCE.cpp b/Source/WebCore/rendering/RenderThemeWinCE.cpp index 4a7bb2546..d89257d04 100644 --- a/Source/WebCore/rendering/RenderThemeWinCE.cpp +++ b/Source/WebCore/rendering/RenderThemeWinCE.cpp @@ -235,10 +235,10 @@ bool RenderThemeWinCE::paintTextField(RenderObject* o, const PaintInfo& i, const return false; } -void RenderThemeWinCE::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWinCE::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { style->resetBorder(); - adjustMenuListButtonStyle(selector, style, e); + adjustMenuListButtonStyle(styleResolver, style, e); } bool RenderThemeWinCE::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r) @@ -352,7 +352,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(StyleResolver* styleResolver, RenderStyle* style, Element* e) const { // Override padding size to match AppKit text positioning. const int padding = 1; @@ -392,21 +392,21 @@ bool RenderThemeWinCE::paintSearchFieldCancelButton(RenderObject* o, const Paint return false; } -void RenderThemeWinCE::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWinCE::adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle* style, Element*) 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(StyleResolver*, RenderStyle* style, Element*) 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(StyleResolver*, RenderStyle* style, Element*) const { IntSize magnifierSize(15, 11); style->setWidth(Length(magnifierSize.width(), Fixed)); @@ -419,7 +419,7 @@ bool RenderThemeWinCE::paintSearchFieldResultsDecoration(RenderObject* o, const return false; } -void RenderThemeWinCE::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWinCE::adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { IntSize magnifierSize(15, 11); style->setWidth(Length(magnifierSize.width(), Fixed)); @@ -432,7 +432,7 @@ bool RenderThemeWinCE::paintSearchFieldResultsButton(RenderObject* o, const Pain return false; } -void RenderThemeWinCE::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeWinCE::adjustMenuListButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { // These are the paddings needed to place the text correctly in the <select> box const int dropDownBoxPaddingTop = 2; @@ -529,7 +529,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(StyleResolver*, RenderStyle* style, Element*) const { const int padding = 1; style->setPaddingLeft(Length(padding, Fixed)); diff --git a/Source/WebCore/rendering/RenderThemeWinCE.h b/Source/WebCore/rendering/RenderThemeWinCE.h index a7df48967..dee237eaf 100644 --- a/Source/WebCore/rendering/RenderThemeWinCE.h +++ b/Source/WebCore/rendering/RenderThemeWinCE.h @@ -81,9 +81,9 @@ namespace WebCore { virtual bool paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r) { return paintTextField(o, i, r); } - virtual void adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const; + virtual void adjustMenuListStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const; + virtual void adjustMenuListButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); @@ -93,26 +93,26 @@ namespace WebCore { virtual bool popupOptionSupportsTextIndent() const { return true; } - virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldCancelButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldDecoration(RenderObject*, const PaintInfo&, const IntRect&) { return false; } - virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsDecorationStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&); - virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual void adjustSearchFieldResultsButtonStyle(StyleResolver*, RenderStyle*, Element*) const; virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&); virtual void themeChanged(); - virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {} - virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {} - virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, Element*) const {} + virtual void adjustButtonStyle(StyleResolver*, RenderStyle* style, Element*) const { } + virtual void adjustTextFieldStyle(StyleResolver*, RenderStyle* style, Element*) const { } + virtual void adjustTextAreaStyle(StyleResolver*, RenderStyle* style, Element*) const { } static void setWebKitIsBeingUnloaded(); diff --git a/Source/WebCore/rendering/RenderTreeAsText.cpp b/Source/WebCore/rendering/RenderTreeAsText.cpp index 79751ba5f..bc6bf26e3 100644 --- a/Source/WebCore/rendering/RenderTreeAsText.cpp +++ b/Source/WebCore/rendering/RenderTreeAsText.cpp @@ -27,6 +27,7 @@ #include "RenderTreeAsText.h" #include "Document.h" +#include "FlowThreadController.h" #include "Frame.h" #include "FrameSelection.h" #include "FrameView.h" @@ -37,11 +38,11 @@ #include "RenderBR.h" #include "RenderDetailsMarker.h" #include "RenderFileUploadControl.h" -#include "RenderFlowThread.h" #include "RenderInline.h" #include "RenderLayer.h" #include "RenderListItem.h" #include "RenderListMarker.h" +#include "RenderNamedFlowThread.h" #include "RenderPart.h" #include "RenderRegion.h" #include "RenderTableCell.h" @@ -76,7 +77,7 @@ namespace WebCore { using namespace HTMLNames; -static void writeLayers(TextStream&, const RenderLayer* rootLayer, RenderLayer*, const IntRect& paintDirtyRect, int indent = 0, RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal); +static void writeLayers(TextStream&, const RenderLayer* rootLayer, RenderLayer*, const LayoutRect& paintDirtyRect, int indent = 0, RenderAsTextBehavior = RenderAsTextBehaviorNormal); static inline bool hasFractions(double val) { @@ -103,6 +104,12 @@ TextStream& operator<<(TextStream& ts, const IntPoint& p) return ts << "(" << p.x() << "," << p.y() << ")"; } +TextStream& operator<<(TextStream& ts, const FractionalLayoutPoint& p) +{ + // FIXME: These should be printed as floats. Keeping them ints for consistency with pervious test expectations. + return ts << "(" << p.x().toInt() << "," << p.y().toInt() << ")"; +} + TextStream& operator<<(TextStream& ts, const FloatPoint& p) { ts << "(" << formatNumberRespectingIntegers(p.x()); @@ -166,7 +173,7 @@ static String getTagName(Node* n) { if (n->isDocumentNode()) return ""; - if (n->isCommentNode()) + if (n->nodeType() == Node::COMMENT_NODE) return "COMMENT"; return n->nodeName(); } @@ -241,7 +248,7 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, RenderBlock* cb = o.containingBlock(); bool adjustForTableCells = cb ? cb->isTableCell() : false; - IntRect r; + LayoutRect r; if (o.isText()) { // FIXME: Would be better to dump the bounding box x and y rather than the first run's x and y, but that would involve updating // many test results. @@ -260,7 +267,7 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, // to clean up the results to dump both the outer box and the intrinsic padding so that both bits of information are // captured by the results. const RenderTableCell& cell = *toRenderTableCell(&o); - r = IntRect(cell.x(), cell.y() + cell.intrinsicPaddingBefore(), cell.width(), cell.height() - cell.intrinsicPaddingBefore() - cell.intrinsicPaddingAfter()); + r = LayoutRect(cell.x(), cell.y() + cell.intrinsicPaddingBefore(), cell.width(), cell.height() - cell.intrinsicPaddingBefore() - cell.intrinsicPaddingAfter()); } else if (o.isBox()) r = toRenderBox(&o)->frameRect(); @@ -268,7 +275,9 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, if (adjustForTableCells) r.move(0, -toRenderTableCell(o.containingBlock())->intrinsicPaddingBefore()); - ts << " " << r; + // FIXME: Convert layout test results to report sub-pixel values, in the meantime using enclosingIntRect + // for consistency with old results. + ts << " " << enclosingIntRect(r); if (!(o.isText() && !o.isBR())) { if (o.isFileUploadControl()) @@ -369,7 +378,7 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, if (o.isTableCell()) { const RenderTableCell& c = *toRenderTableCell(&o); - ts << " [r=" << c.row() << " c=" << c.col() << " rs=" << c.rowSpan() << " cs=" << c.colSpan() << "]"; + ts << " [r=" << c.rowIndex() << " c=" << c.col() << " rs=" << c.rowSpan() << " cs=" << c.colSpan() << "]"; } #if ENABLE(DETAILS) @@ -500,9 +509,9 @@ static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBo y -= toRenderTableCell(o.containingBlock())->intrinsicPaddingBefore(); ts << "text run at (" << x << "," << y << ") width " << logicalWidth; - if (!run.isLeftToRightDirection() || run.m_dirOverride) { + if (!run.isLeftToRightDirection() || run.dirOverride()) { ts << (!run.isLeftToRightDirection() ? " RTL" : " LTR"); - if (run.m_dirOverride) + if (run.dirOverride()) ts << " override"; } ts << ": " @@ -590,9 +599,14 @@ enum LayerPaintPhase { }; static void write(TextStream& ts, RenderLayer& l, - const IntRect& layerBounds, const IntRect& backgroundClipRect, const IntRect& clipRect, const IntRect& outlineClipRect, + const LayoutRect& layerBounds, const LayoutRect& backgroundClipRect, const LayoutRect& clipRect, const LayoutRect& outlineClipRect, LayerPaintPhase paintPhase = LayerPaintPhaseAll, int indent = 0, RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal) { + IntRect adjustedLayoutBounds = pixelSnappedIntRect(layerBounds); + IntRect adjustedBackgroundClipRect = pixelSnappedIntRect(backgroundClipRect); + IntRect adjustedClipRect = pixelSnappedIntRect(clipRect); + IntRect adjustedOutlineClipRect = pixelSnappedIntRect(outlineClipRect); + writeIndent(ts, indent); ts << "layer "; @@ -600,15 +614,15 @@ static void write(TextStream& ts, RenderLayer& l, if (behavior & RenderAsTextShowAddresses) ts << static_cast<const void*>(&l) << " "; - ts << layerBounds; + ts << adjustedLayoutBounds; - if (!layerBounds.isEmpty()) { - if (!backgroundClipRect.contains(layerBounds)) - ts << " backgroundClip " << backgroundClipRect; - if (!clipRect.contains(layerBounds)) - ts << " clip " << clipRect; - if (!outlineClipRect.contains(layerBounds)) - ts << " outlineClip " << outlineClipRect; + if (!adjustedLayoutBounds.isEmpty()) { + if (!adjustedBackgroundClipRect.contains(adjustedLayoutBounds)) + ts << " backgroundClip " << adjustedBackgroundClipRect; + if (!adjustedClipRect.contains(adjustedLayoutBounds)) + ts << " clip " << adjustedClipRect; + if (!adjustedOutlineClipRect.contains(adjustedLayoutBounds)) + ts << " outlineClip " << adjustedOutlineClipRect; } if (l.renderer()->hasOverflowClip()) { @@ -630,7 +644,7 @@ static void write(TextStream& ts, RenderLayer& l, #if USE(ACCELERATED_COMPOSITING) if (behavior & RenderAsTextShowCompositedLayers) { if (l.isComposited()) - ts << " (composited, bounds " << l.backing()->compositedBounds() << ")"; + ts << " (composited, bounds=" << l.backing()->compositedBounds() << ", drawsContent=" << l.backing()->graphicsLayer()->drawsContent() << ", paints into ancestor=" << l.backing()->paintsIntoCompositedAncestor() << ")"; } #else UNUSED_PARAM(behavior); @@ -642,21 +656,22 @@ static void write(TextStream& ts, RenderLayer& l, write(ts, *l.renderer(), indent + 1, behavior); } -static void writeRenderFlowThreads(TextStream& ts, RenderView* renderView, const RenderLayer* rootLayer, - const IntRect& paintRect, int indent, RenderAsTextBehavior behavior) +static void writeRenderNamedFlowThreads(TextStream& ts, RenderView* renderView, const RenderLayer* rootLayer, + const LayoutRect& paintRect, int indent, RenderAsTextBehavior behavior) { - const RenderFlowThreadList* list = renderView->renderFlowThreadList(); - if (!list || list->isEmpty()) + if (!renderView->hasRenderNamedFlowThreads()) return; + const RenderNamedFlowThreadList* list = renderView->flowThreadController()->renderNamedFlowThreadList(); + writeIndent(ts, indent); ts << "Flow Threads\n"; - for (RenderFlowThreadList::const_iterator iter = list->begin(); iter != list->end(); ++iter) { - const RenderFlowThread* renderFlowThread = *iter; + for (RenderNamedFlowThreadList::const_iterator iter = list->begin(); iter != list->end(); ++iter) { + const RenderNamedFlowThread* renderFlowThread = *iter; writeIndent(ts, indent + 1); - ts << "Thread with flow-name '" << renderFlowThread->flowThread() << "'\n"; + ts << "Thread with flow-name '" << renderFlowThread->flowThreadName() << "'\n"; RenderLayer* layer = renderFlowThread->layer(); writeLayers(ts, rootLayer, layer, paintRect, indent + 2, behavior); @@ -665,7 +680,7 @@ static void writeRenderFlowThreads(TextStream& ts, RenderView* renderView, const const RenderRegionList& flowThreadRegionList = renderFlowThread->renderRegionList(); if (!flowThreadRegionList.isEmpty()) { writeIndent(ts, indent + 1); - ts << "Regions for flow '"<< renderFlowThread->flowThread() << "'\n"; + ts << "Regions for flow '"<< renderFlowThread->flowThreadName() << "'\n"; for (RenderRegionList::const_iterator itRR = flowThreadRegionList.begin(); itRR != flowThreadRegionList.end(); ++itRR) { RenderRegion* renderRegion = *itRR; writeIndent(ts, indent + 2); @@ -690,24 +705,23 @@ static void writeRenderFlowThreads(TextStream& ts, RenderView* renderView, const } static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLayer* l, - const IntRect& paintRect, int indent, RenderAsTextBehavior behavior) + const LayoutRect& paintRect, int indent, RenderAsTextBehavior behavior) { // FIXME: Apply overflow to the root layer to not break every test. Complete hack. Sigh. - IntRect paintDirtyRect(paintRect); + LayoutRect paintDirtyRect(paintRect); if (rootLayer == l) { - paintDirtyRect.setWidth(max(paintDirtyRect.width(), rootLayer->renderBox()->maxXLayoutOverflow())); - paintDirtyRect.setHeight(max(paintDirtyRect.height(), rootLayer->renderBox()->maxYLayoutOverflow())); - l->setSize(l->size().expandedTo(l->renderBox()->maxLayoutOverflow())); + paintDirtyRect.setWidth(max<LayoutUnit>(paintDirtyRect.width(), rootLayer->renderBox()->maxXLayoutOverflow())); + paintDirtyRect.setHeight(max<LayoutUnit>(paintDirtyRect.height(), rootLayer->renderBox()->maxYLayoutOverflow())); + l->setSize(l->size().expandedTo(pixelSnappedIntSize(l->renderBox()->maxLayoutOverflow(), LayoutPoint(0, 0)))); } // Calculate the clip rects we should use. - IntRect layerBounds; + LayoutRect layerBounds; ClipRect damageRect, clipRectToApply, outlineRect; l->calculateRects(rootLayer, 0, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, true); // Ensure our lists are up-to-date. - l->updateZOrderLists(); - l->updateNormalFlowList(); + l->updateLayerListsIfNeeded(); bool shouldPaint = (behavior & RenderAsTextShowAllLayers) ? true : l->intersectsDamageRect(layerBounds, damageRect.rect(), rootLayer); Vector<RenderLayer*>* negList = l->negZOrderList(); @@ -755,7 +769,7 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye // so we have to treat it as a special case. if (l->renderer()->isRenderView()) { RenderView* renderView = toRenderView(l->renderer()); - writeRenderFlowThreads(ts, renderView, rootLayer, paintDirtyRect, indent, behavior); + writeRenderNamedFlowThreads(ts, renderView, rootLayer, paintDirtyRect, indent, behavior); } } diff --git a/Source/WebCore/rendering/RenderTreeAsText.h b/Source/WebCore/rendering/RenderTreeAsText.h index 26cc065cc..849943068 100644 --- a/Source/WebCore/rendering/RenderTreeAsText.h +++ b/Source/WebCore/rendering/RenderTreeAsText.h @@ -33,6 +33,7 @@ namespace WebCore { class Element; +class FractionalLayoutPoint; class FloatPoint; class FloatSize; class Frame; @@ -70,6 +71,7 @@ static void writeRenderObject(TextStream& ts, const RenderObject& o, RenderAsTex TextStream& operator<<(TextStream&, const IntPoint&); TextStream& operator<<(TextStream&, const IntRect&); +TextStream& operator<<(TextStream&, const FractionalLayoutPoint&); TextStream& operator<<(TextStream&, const FloatPoint&); TextStream& operator<<(TextStream&, const FloatSize&); diff --git a/Source/WebCore/rendering/RenderVideo.cpp b/Source/WebCore/rendering/RenderVideo.cpp index 1fc87a7d2..37f2f0844 100644 --- a/Source/WebCore/rendering/RenderVideo.cpp +++ b/Source/WebCore/rendering/RenderVideo.cpp @@ -43,13 +43,6 @@ #include "RenderFullScreen.h" #endif -#if USE(ACCELERATED_COMPOSITING) -#include "RenderLayer.h" -#include "RenderLayerBacking.h" -#endif - -using namespace std; - namespace WebCore { using namespace HTMLNames; @@ -166,7 +159,7 @@ IntRect RenderVideo::videoBox() const else elementSize = intrinsicSize(); - IntRect contentRect = contentBoxRect(); + IntRect contentRect = pixelSnappedIntRect(contentBoxRect()); if (elementSize.isEmpty() || contentRect.isEmpty()) return IntRect(); @@ -225,9 +218,9 @@ void RenderVideo::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf if (displayingPoster) paintIntoRect(paintInfo.context, rect); else if (document()->view() && document()->view()->paintBehavior() & PaintBehaviorFlattenCompositingLayers) - mediaPlayer->paintCurrentFrameInContext(paintInfo.context, rect); + mediaPlayer->paintCurrentFrameInContext(paintInfo.context, pixelSnappedIntRect(rect)); else - mediaPlayer->paint(paintInfo.context, rect); + mediaPlayer->paint(paintInfo.context, pixelSnappedIntRect(rect)); } void RenderVideo::layout() @@ -262,7 +255,7 @@ void RenderVideo::updatePlayer() } #if USE(ACCELERATED_COMPOSITING) - layer()->contentChanged(RenderLayer::VideoChanged); + contentChanged(VideoChanged); #endif IntRect videoBounds = videoBox(); diff --git a/Source/WebCore/rendering/RenderView.cpp b/Source/WebCore/rendering/RenderView.cpp index cd3893a55..4a3a2bc83 100644 --- a/Source/WebCore/rendering/RenderView.cpp +++ b/Source/WebCore/rendering/RenderView.cpp @@ -25,14 +25,15 @@ #include "Document.h" #include "Element.h" #include "FloatQuad.h" +#include "FlowThreadController.h" #include "Frame.h" #include "FrameView.h" #include "GraphicsContext.h" #include "HTMLFrameOwnerElement.h" #include "HitTestResult.h" #include "Page.h" -#include "RenderFlowThread.h" #include "RenderLayer.h" +#include "RenderNamedFlowThread.h" #include "RenderSelectionInfo.h" #include "RenderWidget.h" #include "RenderWidgetProtector.h" @@ -54,10 +55,8 @@ RenderView::RenderView(Node* node, FrameView* view) , m_maximalOutlineSize(0) , m_pageLogicalHeight(0) , m_pageLogicalHeightChanged(false) - , m_isRenderFlowThreadOrderDirty(false) , m_layoutState(0) , m_layoutStateDisableCount(0) - , m_currentRenderFlowThread(0) { // Clear our anonymous bit, set because RenderObject assumes // any renderer with document as the node is anonymous. @@ -69,7 +68,7 @@ RenderView::RenderView(Node* node, FrameView* view) m_minPreferredLogicalWidth = 0; m_maxPreferredLogicalWidth = 0; - setPreferredLogicalWidthsDirty(true, false); + setPreferredLogicalWidthsDirty(true, MarkOnlyThis); setPositioned(true); // to 0,0 :) } @@ -78,6 +77,11 @@ RenderView::~RenderView() { } +bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result) +{ + return layer()->hitTest(request, result); +} + void RenderView::computeLogicalHeight() { if (!printing() && m_frameView) @@ -95,8 +99,6 @@ void RenderView::computePreferredLogicalWidths() ASSERT(preferredLogicalWidthsDirty()); RenderBlock::computePreferredLogicalWidths(); - - m_maxPreferredLogicalWidth = m_minPreferredLogicalWidth; } bool RenderView::isChildAllowed(RenderObject* child, RenderStyle*) const @@ -115,10 +117,13 @@ void RenderView::layout() // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account. bool relayoutChildren = !printing() && (!m_frameView || width() != viewWidth() || height() != viewHeight()); if (relayoutChildren) { - setChildNeedsLayout(true, false); + setChildNeedsLayout(true, MarkOnlyThis); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->style()->logicalHeight().isPercent() || child->style()->logicalMinHeight().isPercent() || child->style()->logicalMaxHeight().isPercent()) - child->setChildNeedsLayout(true, false); + if ((child->isBox() && toRenderBox(child)->hasRelativeLogicalHeight()) + || child->style()->logicalHeight().isPercent() + || child->style()->logicalMinHeight().isPercent() + || child->style()->logicalMaxHeight().isPercent()) + child->setChildNeedsLayout(true, MarkOnlyThis); } } @@ -134,8 +139,8 @@ void RenderView::layout() if (needsLayout()) { RenderBlock::layout(); - if (hasRenderFlowThreads()) - layoutRenderFlowThreads(); + if (hasRenderNamedFlowThreads()) + flowThreadController()->layoutRenderNamedFlowThreads(); } ASSERT(layoutDelta() == LayoutSize()); @@ -145,7 +150,7 @@ void RenderView::layout() setNeedsLayout(false); } -void RenderView::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, bool* wasFixed) const +void RenderView::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, ApplyContainerFlipOrNot, bool* wasFixed) const { // If a container was specified, and was not 0 or the RenderView, // then we should have found it by now. @@ -214,6 +219,8 @@ void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // If we ever require layout but receive a paint anyway, something has gone horribly wrong. ASSERT(!needsLayout()); + // RenderViews should never be called to paint with an offset not on device pixels. + ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffset); paintObject(paintInfo, paintOffset); } @@ -246,8 +253,8 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) } #if USE(ACCELERATED_COMPOSITING) - if (RenderLayer* compositingLayer = layer->enclosingCompositingLayer()) { - if (!compositingLayer->backing()->paintingGoesToWindow()) { + if (RenderLayer* compositingLayer = layer->enclosingCompositingLayerForRepaint()) { + if (!compositingLayer->backing()->paintsIntoWindow()) { frameView()->setCannotBlitToWindow(); break; } @@ -291,18 +298,21 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) } } -bool RenderView::shouldRepaint(const IntRect& r) const +bool RenderView::shouldRepaint(const LayoutRect& r) const { if (printing() || r.width() == 0 || r.height() == 0) return false; if (!m_frameView) return false; - + + if (m_frameView->repaintsDisabled()) + return false; + return true; } -void RenderView::repaintViewRectangle(const IntRect& ur, bool immediate) +void RenderView::repaintViewRectangle(const LayoutRect& ur, bool immediate) { if (!shouldRepaint(ur)) return; @@ -311,23 +321,22 @@ void RenderView::repaintViewRectangle(const IntRect& ur, bool immediate) // or even invisible. Element* elt = document()->ownerElement(); if (!elt) - m_frameView->repaintContentRectangle(ur, immediate); + m_frameView->repaintContentRectangle(pixelSnappedIntRect(ur), immediate); else if (RenderBox* obj = elt->renderBox()) { - IntRect vr = viewRect(); - IntRect r = intersection(ur, vr); + LayoutRect vr = viewRect(); + LayoutRect r = intersection(ur, vr); // Subtract out the contentsX and contentsY offsets to get our coords within the viewing // rectangle. r.moveBy(-vr.location()); - + // FIXME: Hardcoded offsets here are not good. - r.move(obj->borderLeft() + obj->paddingLeft(), - obj->borderTop() + obj->paddingTop()); + r.moveBy(obj->contentBoxRect().location()); obj->repaintRectangle(r, immediate); } } -void RenderView::repaintRectangleInViewAndCompositedLayers(const IntRect& ur, bool immediate) +void RenderView::repaintRectangleInViewAndCompositedLayers(const LayoutRect& ur, bool immediate) { if (!shouldRepaint(ur)) return; @@ -336,11 +345,11 @@ void RenderView::repaintRectangleInViewAndCompositedLayers(const IntRect& ur, bo #if USE(ACCELERATED_COMPOSITING) if (compositor()->inCompositingMode()) - compositor()->repaintCompositedLayersAbsoluteRect(ur); + compositor()->repaintCompositedLayersAbsoluteRect(pixelSnappedIntRect(ur)); #endif } -void RenderView::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed) const +void RenderView::computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect& rect, bool fixed) const { // If a container was specified, and was not 0 or the RenderView, // then we should have found it by now. @@ -414,12 +423,12 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const } // Now create a single bounding box rect that encloses the whole selection. - IntRect selRect; + LayoutRect selRect; SelectionMap::iterator end = selectedObjects.end(); for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) { RenderSelectionInfo* info = i->second; // RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates. - IntRect currRect = info->rect(); + LayoutRect currRect = info->rect(); if (RenderBoxModelObject* repaintContainer = info->repaintContainer()) { FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect)); currRect = absQuad.enclosingBoundingBox(); @@ -427,7 +436,7 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const selRect.unite(currRect); delete info; } - return selRect; + return pixelSnappedIntRect(selRect); } #if USE(ACCELERATED_COMPOSITING) @@ -700,21 +709,21 @@ void RenderView::notifyWidgets(WidgetNotification notification) releaseWidgets(renderWidgets); } -IntRect RenderView::viewRect() const +LayoutRect RenderView::viewRect() const { if (printing()) - return IntRect(IntPoint(), size()); + return LayoutRect(LayoutPoint(), size()); if (m_frameView) return m_frameView->visibleContentRect(); - return IntRect(); + return LayoutRect(); } IntRect RenderView::unscaledDocumentRect() const { - IntRect overflowRect(layoutOverflowRect()); + LayoutRect overflowRect(layoutOverflowRect()); flipForWritingMode(overflowRect); - return overflowRect; + return pixelSnappedIntRect(overflowRect); } LayoutRect RenderView::backgroundRect(RenderBox* backgroundRenderer) const @@ -882,64 +891,62 @@ void RenderView::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl RenderBlock::styleDidChange(diff, oldStyle); for (RenderObject* renderer = firstChild(); renderer; renderer = renderer->nextSibling()) { - if (renderer->isRenderFlowThread()) { - RenderFlowThread* flowRenderer = toRenderFlowThread(renderer); + if (renderer->isRenderNamedFlowThread()) { + RenderNamedFlowThread* flowRenderer = toRenderNamedFlowThread(renderer); flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(style())); } } } -RenderFlowThread* RenderView::ensureRenderFlowThreadWithName(const AtomicString& flowThread) +bool RenderView::hasRenderNamedFlowThreads() const { - if (!m_renderFlowThreadList) - m_renderFlowThreadList = adoptPtr(new RenderFlowThreadList()); - else { - for (RenderFlowThreadList::iterator iter = m_renderFlowThreadList->begin(); iter != m_renderFlowThreadList->end(); ++iter) { - RenderFlowThread* flowRenderer = *iter; - if (flowRenderer->flowThread() == flowThread) - return flowRenderer; - } - } + return m_flowThreadController && m_flowThreadController->hasRenderNamedFlowThreads(); +} - RenderFlowThread* flowRenderer = new (renderArena()) RenderFlowThread(document(), flowThread); - flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(style())); - addChild(flowRenderer); +FlowThreadController* RenderView::flowThreadController() +{ + if (!m_flowThreadController) + m_flowThreadController = FlowThreadController::create(this); - m_renderFlowThreadList->add(flowRenderer); - setIsRenderFlowThreadOrderDirty(true); + return m_flowThreadController.get(); +} - return flowRenderer; +RenderBlock::IntervalArena* RenderView::intervalArena() +{ + if (!m_intervalArena) + m_intervalArena = IntervalArena::create(); + return m_intervalArena.get(); } -void RenderView::layoutRenderFlowThreads() +void RenderView::setFixedPositionedObjectsNeedLayout() { - ASSERT(m_renderFlowThreadList); + ASSERT(m_frameView); - if (isRenderFlowThreadOrderDirty()) { - // Arrange the thread list according to dependencies. - RenderFlowThreadList sortedList; - for (RenderFlowThreadList::iterator iter = m_renderFlowThreadList->begin(); iter != m_renderFlowThreadList->end(); ++iter) { - RenderFlowThread* flowRenderer = *iter; - if (sortedList.contains(flowRenderer)) - continue; - flowRenderer->pushDependencies(sortedList); - sortedList.add(flowRenderer); - } - m_renderFlowThreadList->swap(sortedList); - setIsRenderFlowThreadOrderDirty(false); - } + PositionedObjectsListHashSet* positionedObjects = this->positionedObjects(); + if (!positionedObjects) + return; - for (RenderFlowThreadList::iterator iter = m_renderFlowThreadList->begin(); iter != m_renderFlowThreadList->end(); ++iter) { - RenderFlowThread* flowRenderer = *iter; - flowRenderer->layoutIfNeeded(); + PositionedObjectsListHashSet::const_iterator end = positionedObjects->end(); + for (PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) { + RenderBox* currBox = *it; + currBox->setNeedsLayout(true); } } -RenderBlock::IntervalArena* RenderView::intervalArena() +void RenderView::insertFixedPositionedObject(RenderBox* object) { - if (!m_intervalArena) - m_intervalArena = IntervalArena::create(); - return m_intervalArena.get(); + if (!m_positionedObjects) + m_positionedObjects = adoptPtr(new PositionedObjectsListHashSet); + + m_positionedObjects->add(object); +} + +void RenderView::removeFixedPositionedObject(RenderBox* object) +{ + if (!m_positionedObjects) + return; + + m_positionedObjects->remove(object); } } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderView.h b/Source/WebCore/rendering/RenderView.h index 66000942e..1371e136e 100644 --- a/Source/WebCore/rendering/RenderView.h +++ b/Source/WebCore/rendering/RenderView.h @@ -26,37 +26,38 @@ #include "LayoutState.h" #include "PODFreeListArena.h" #include "RenderBlock.h" -#include <wtf/ListHashSet.h> #include <wtf/OwnPtr.h> namespace WebCore { -class RenderFlowThread; +class FlowThreadController; class RenderWidget; #if USE(ACCELERATED_COMPOSITING) class RenderLayerCompositor; #endif -typedef ListHashSet<RenderFlowThread*> RenderFlowThreadList; - class RenderView : public RenderBlock { public: RenderView(Node*, FrameView*); virtual ~RenderView(); - virtual const char* renderName() const { return "RenderView"; } + bool hitTest(const HitTestRequest&, HitTestResult&); + + virtual const char* renderName() const OVERRIDE { return "RenderView"; } - virtual bool isRenderView() const { return true; } + virtual bool isRenderView() const OVERRIDE { return true; } - virtual bool requiresLayer() const { return true; } + virtual bool requiresLayer() const OVERRIDE { return true; } - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; - virtual void layout(); - virtual void computeLogicalWidth(); - virtual void computeLogicalHeight(); - virtual void computePreferredLogicalWidths(); + virtual void layout() OVERRIDE; + virtual void computeLogicalWidth() OVERRIDE; + virtual void computeLogicalHeight() OVERRIDE; + // FIXME: This override is not needed and should be removed + // it only exists to make computePreferredLogicalWidths public. + virtual void computePreferredLogicalWidths() OVERRIDE; // The same as the FrameView's layoutHeight/layoutWidth but with null check guards. int viewHeight() const; @@ -68,14 +69,14 @@ public: FrameView* frameView() const { return m_frameView; } - virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect&, bool fixed = false) const; - virtual void repaintViewRectangle(const IntRect&, bool immediate = false); + virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect&, bool fixed = false) const; + virtual void repaintViewRectangle(const LayoutRect&, bool immediate = false); // Repaint the view, and all composited layers that intersect the given absolute rectangle. // FIXME: ideally we'd never have to do this, if all repaints are container-relative. - virtual void repaintRectangleInViewAndCompositedLayers(const IntRect&, bool immediate = false); + virtual void repaintRectangleInViewAndCompositedLayers(const LayoutRect&, bool immediate = false); virtual void paint(PaintInfo&, const LayoutPoint&); - virtual void paintBoxDecorations(PaintInfo&, const IntPoint&); + virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&) OVERRIDE; enum SelectionRepaintMode { RepaintNewXOROld, RepaintNewMinusOld, RepaintNothing }; void setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode = RepaintNewXOROld); @@ -98,7 +99,7 @@ public: #endif int maximalOutlineSize() const { return m_maximalOutlineSize; } - virtual IntRect viewRect() const; + virtual LayoutRect viewRect() const OVERRIDE; void updateWidgetPositions(); void addWidget(RenderWidget*); @@ -172,27 +173,21 @@ public: IntRect documentRect() const; - RenderFlowThread* ensureRenderFlowThreadWithName(const AtomicString& flowThread); - bool hasRenderFlowThreads() const { return m_renderFlowThreadList && !m_renderFlowThreadList->isEmpty(); } - void layoutRenderFlowThreads(); - bool isRenderFlowThreadOrderDirty() const { return m_isRenderFlowThreadOrderDirty; } - void setIsRenderFlowThreadOrderDirty(bool dirty) - { - m_isRenderFlowThreadOrderDirty = dirty; - if (dirty) - setNeedsLayout(true); - } - const RenderFlowThreadList* renderFlowThreadList() const { return m_renderFlowThreadList.get(); } - - RenderFlowThread* currentRenderFlowThread() const { return m_currentRenderFlowThread; } - void setCurrentRenderFlowThread(RenderFlowThread* flowThread) { m_currentRenderFlowThread = flowThread; } + bool hasRenderNamedFlowThreads() const; + FlowThreadController* flowThreadController(); void styleDidChange(StyleDifference, const RenderStyle* oldStyle); IntervalArena* intervalArena(); + IntSize viewportSize() const { return document()->viewportSize(); } + + void setFixedPositionedObjectsNeedLayout(); + void insertFixedPositionedObject(RenderBox*); + void removeFixedPositionedObject(RenderBox*); + protected: - virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, bool* wasFixed = 0) const; + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const; virtual bool requiresColumns(int desiredColumnCount) const OVERRIDE; @@ -200,7 +195,7 @@ private: virtual void calcColumnWidth() OVERRIDE; virtual ColumnInfo::PaginationUnit paginationUnit() const OVERRIDE; - bool shouldRepaint(const IntRect& r) const; + bool shouldRepaint(const LayoutRect&) const; // These functions may only be accessed by LayoutStateMaintainer. void pushLayoutState(RenderFlowThread*, bool regionsChanged); @@ -266,18 +261,19 @@ protected: typedef HashSet<RenderWidget*> RenderWidgetSet; RenderWidgetSet m_widgets; - + + typedef HashSet<RenderBox*> RenderBoxSet; + OwnPtr<RenderBoxSet> m_fixedPositionedElements; + private: unsigned m_pageLogicalHeight; bool m_pageLogicalHeightChanged; - bool m_isRenderFlowThreadOrderDirty; LayoutState* m_layoutState; unsigned m_layoutStateDisableCount; #if USE(ACCELERATED_COMPOSITING) OwnPtr<RenderLayerCompositor> m_compositor; #endif - OwnPtr<RenderFlowThreadList> m_renderFlowThreadList; - RenderFlowThread* m_currentRenderFlowThread; + OwnPtr<FlowThreadController> m_flowThreadController; RefPtr<IntervalArena> m_intervalArena; }; diff --git a/Source/WebCore/rendering/RenderWidget.cpp b/Source/WebCore/rendering/RenderWidget.cpp index 55802c4c2..c49d8f201 100644 --- a/Source/WebCore/rendering/RenderWidget.cpp +++ b/Source/WebCore/rendering/RenderWidget.cpp @@ -140,12 +140,20 @@ RenderWidget::~RenderWidget() clearWidget(); } -bool RenderWidget::setWidgetGeometry(const IntRect& frame) +// Widgets are always placed on integer boundaries, so rounding the size is actually +// the desired behavior. This function is here because it's otherwise seldom what we +// want to do with a LayoutRect. +static inline IntRect roundedIntRect(const LayoutRect& rect) +{ + return IntRect(roundedIntPoint(rect.location()), roundedIntSize(rect.size())); +} + +bool RenderWidget::setWidgetGeometry(const LayoutRect& frame) { if (!node()) return false; - IntRect clipRect = enclosingLayer()->childrenClipRect(); + IntRect clipRect = roundedIntRect(enclosingLayer()->childrenClipRect()); bool clipChanged = m_clipRect != clipRect; bool boundsChanged = m_widget->frameRect() != frame; @@ -156,7 +164,7 @@ bool RenderWidget::setWidgetGeometry(const IntRect& frame) RenderWidgetProtector protector(this); RefPtr<Node> protectedNode(node()); - m_widget->setFrameRect(frame); + m_widget->setFrameRect(roundedIntRect(frame)); #if USE(ACCELERATED_COMPOSITING) if (hasLayer() && layer()->isComposited()) @@ -168,11 +176,11 @@ bool RenderWidget::setWidgetGeometry(const IntRect& frame) bool RenderWidget::updateWidgetGeometry() { - IntRect contentBox = contentBoxRect(); + IntRect contentBox = pixelSnappedIntRect(contentBoxRect()); if (!m_widget->transformsAffectFrameRect()) return setWidgetGeometry(absoluteContentBox()); - IntRect absoluteContentBox = IntRect(localToAbsoluteQuad(FloatQuad(contentBox)).boundingBox()); + IntRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox)).boundingBox()); if (m_widget->isFrameView()) { contentBox.setLocation(absoluteContentBox.location()); return setWidgetGeometry(contentBox); @@ -270,17 +278,18 @@ void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. paintInfo.context->save(); - paintInfo.context->addRoundedRectClip(style()->getRoundedBorderFor(borderRect)); + paintInfo.context->addRoundedRectClip(style()->getRoundedBorderFor(borderRect, view())); } if (m_widget) { // Tell the widget to paint now. This is the only time the widget is allowed // to paint itself. That way it will composite properly with z-indexed layers. - LayoutPoint widgetLocation = m_widget->frameRect().location(); - LayoutPoint paintLocation(adjustedPaintOffset.x() + borderLeft() + paddingLeft(), adjustedPaintOffset.y() + borderTop() + paddingTop()); - LayoutRect paintRect = paintInfo.rect; + IntPoint widgetLocation = m_widget->frameRect().location(); + IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + paddingLeft()), + roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop())); + IntRect paintRect = paintInfo.rect; - LayoutSize widgetPaintOffset = paintLocation - widgetLocation; + IntSize widgetPaintOffset = paintLocation - widgetLocation; // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer, // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing. if (!widgetPaintOffset.isZero()) { diff --git a/Source/WebCore/rendering/RenderWidget.h b/Source/WebCore/rendering/RenderWidget.h index 8bfa30ba4..54a7a771c 100644 --- a/Source/WebCore/rendering/RenderWidget.h +++ b/Source/WebCore/rendering/RenderWidget.h @@ -70,7 +70,7 @@ private: virtual void setSelectionState(SelectionState); virtual void setOverlapTestResult(bool); - bool setWidgetGeometry(const IntRect&); + bool setWidgetGeometry(const LayoutRect&); bool updateWidgetGeometry(); RefPtr<Widget> m_widget; diff --git a/Source/WebCore/rendering/RenderingAllInOne.cpp b/Source/WebCore/rendering/RenderingAllInOne.cpp index b52e2908a..ff8e0731e 100644 --- a/Source/WebCore/rendering/RenderingAllInOne.cpp +++ b/Source/WebCore/rendering/RenderingAllInOne.cpp @@ -74,6 +74,7 @@ #include "RenderMediaControls.cpp" #include "RenderMenuList.cpp" #include "RenderMeter.cpp" +#include "RenderMultiColumnBlock.cpp" #include "RenderObject.cpp" #include "RenderObjectChildList.cpp" #include "RenderPart.cpp" diff --git a/Source/WebCore/rendering/RootInlineBox.cpp b/Source/WebCore/rendering/RootInlineBox.cpp index c56560065..9b973b3b2 100644 --- a/Source/WebCore/rendering/RootInlineBox.cpp +++ b/Source/WebCore/rendering/RootInlineBox.cpp @@ -100,6 +100,16 @@ bool RootInlineBox::isHyphenated() const return false; } +LayoutUnit RootInlineBox::baselinePosition(FontBaseline baselineType) const +{ + return boxModelObject()->baselinePosition(baselineType, isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); +} + +LayoutUnit RootInlineBox::lineHeight() const +{ + return boxModelObject()->lineHeight(isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); +} + bool RootInlineBox::lineCanAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth) { // First sanity-check the unoverflowed width of the whole line to see if there is sufficient room. @@ -196,7 +206,7 @@ void RootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, InlineFlowBox::paint(paintInfo, paintOffset, lineTop, lineBottom); paintEllipsisBox(paintInfo, paintOffset, lineTop, lineBottom); #if PLATFORM(MAC) - RenderStyle* styleToUse = renderer()->style(m_firstLine); + RenderStyle* styleToUse = renderer()->style(isFirstLineStyle()); if (styleToUse->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) paintCustomHighlight(paintInfo, paintOffset, styleToUse->highlight()); #endif @@ -278,7 +288,7 @@ LayoutUnit RootInlineBox::alignBoxesInBlockDirection(LayoutUnit heightOfBlock, G setLineTopBottomPositions(lineTop, lineBottom, heightOfBlock, heightOfBlock + maxHeight); setPaginatedLineWidth(block()->availableLogicalWidthForContent(heightOfBlock)); - int annotationsAdjustment = beforeAnnotationsAdjustment(); + LayoutUnit annotationsAdjustment = beforeAnnotationsAdjustment(); if (annotationsAdjustment) { // FIXME: Need to handle pagination here. We might have to move to the next page/column as a result of the // ruby expansion. @@ -295,9 +305,9 @@ LayoutUnit RootInlineBox::alignBoxesInBlockDirection(LayoutUnit heightOfBlock, G return heightOfBlock + maxHeight; } -int RootInlineBox::beforeAnnotationsAdjustment() const +LayoutUnit RootInlineBox::beforeAnnotationsAdjustment() const { - int result = 0; + LayoutUnit result = 0; if (!renderer()->style()->isFlippedLinesWritingMode()) { // Annotations under the previous line may push us down. @@ -308,18 +318,18 @@ int RootInlineBox::beforeAnnotationsAdjustment() const return result; // Annotations over this line may push us further down. - int highestAllowedPosition = prevRootBox() ? min(prevRootBox()->lineBottom(), lineTop()) + result : block()->borderBefore(); + LayoutUnit highestAllowedPosition = prevRootBox() ? min(prevRootBox()->lineBottom(), lineTop()) + result : static_cast<LayoutUnit>(block()->borderBefore()); result = computeOverAnnotationAdjustment(highestAllowedPosition); } else { // Annotations under this line may push us up. if (hasAnnotationsBefore()) - result = computeUnderAnnotationAdjustment(prevRootBox() ? prevRootBox()->lineBottom() : block()->borderBefore()); + result = computeUnderAnnotationAdjustment(prevRootBox() ? prevRootBox()->lineBottom() : static_cast<LayoutUnit>(block()->borderBefore())); if (!prevRootBox() || !prevRootBox()->hasAnnotationsAfter()) return result; // We have to compute the expansion for annotations over the previous line to see how much we should move. - int lowestAllowedPosition = max(prevRootBox()->lineBottom(), lineTop()) - result; + LayoutUnit lowestAllowedPosition = max(prevRootBox()->lineBottom(), lineTop()) - result; result = prevRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition); } @@ -399,7 +409,7 @@ LayoutUnit RootInlineBox::lineSnapAdjustment(LayoutUnit delta) const // Otherwise we're in the middle of the grid somewhere. Just push to the next line. LayoutUnit baselineOffset = currentBaselinePosition - firstBaselinePosition; - LayoutUnit remainder = baselineOffset % gridLineHeight; + LayoutUnit remainder = roundToInt(baselineOffset) % roundToInt(gridLineHeight); LayoutUnit result = delta; if (remainder) result += gridLineHeight - remainder; @@ -535,6 +545,29 @@ LayoutUnit RootInlineBox::selectionTop() const return prevBottom; } +LayoutUnit RootInlineBox::selectionTopAdjustedForPrecedingBlock() const +{ + LayoutUnit top = selectionTop(); + + RenderObject::SelectionState blockSelectionState = root()->block()->selectionState(); + if (blockSelectionState != RenderObject::SelectionInside && blockSelectionState != RenderObject::SelectionEnd) + return top; + + LayoutSize offsetToBlockBefore; + if (RenderBlock* block = root()->block()->blockBeforeWithinSelectionRoot(offsetToBlockBefore)) { + if (RootInlineBox* lastLine = block->lastRootBox()) { + RenderObject::SelectionState lastLineSelectionState = lastLine->selectionState(); + if (lastLineSelectionState != RenderObject::SelectionInside && lastLineSelectionState != RenderObject::SelectionStart) + return top; + + LayoutUnit lastLineSelectionBottom = lastLine->selectionBottom() + offsetToBlockBefore.height(); + top = max(top, lastLineSelectionBottom); + } + } + + return top; +} + LayoutUnit RootInlineBox::selectionBottom() const { LayoutUnit selectionBottom = m_lineBottom; @@ -695,7 +728,7 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb // Replaced boxes will return 0 for the line-height if line-box-contain says they are // not to be included. if (box->renderer()->isReplaced()) { - if (renderer()->style(m_firstLine)->lineBoxContain() & LineBoxContainReplaced) { + if (renderer()->style(isFirstLineStyle())->lineBoxContain() & LineBoxContainReplaced) { ascent = box->baselinePosition(baselineType()); descent = box->lineHeight() - ascent; @@ -720,8 +753,8 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb bool setUsedFont = false; bool setUsedFontWithLeading = false; - if (usedFonts && !usedFonts->isEmpty() && (includeFont || (box->renderer()->style(m_firstLine)->lineHeight().isNegative() && includeLeading))) { - usedFonts->append(box->renderer()->style(m_firstLine)->font().primaryFont()); + if (usedFonts && !usedFonts->isEmpty() && (includeFont || (box->renderer()->style(isFirstLineStyle())->lineHeight().isNegative() && includeLeading))) { + usedFonts->append(box->renderer()->style(isFirstLineStyle())->font().primaryFont()); for (size_t i = 0; i < usedFonts->size(); ++i) { const FontMetrics& fontMetrics = usedFonts->at(i)->fontMetrics(); LayoutUnit usedFontAscent = fontMetrics.ascent(baselineType()); @@ -746,8 +779,8 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb // If leading is included for the box, then we compute that box. if (includeLeading && !setUsedFontWithLeading) { - int ascentWithLeading = box->baselinePosition(baselineType()); - int descentWithLeading = box->lineHeight() - ascentWithLeading; + LayoutUnit ascentWithLeading = box->baselinePosition(baselineType()); + LayoutUnit descentWithLeading = box->lineHeight() - ascentWithLeading; setAscentAndDescent(ascent, descent, ascentWithLeading, descentWithLeading, ascentDescentSet); // Examine the font box for inline flows and text boxes to see if any part of it is above the baseline. @@ -759,8 +792,8 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb } if (includeFontForBox(box) && !setUsedFont) { - int fontAscent = box->renderer()->style(m_firstLine)->fontMetrics().ascent(); - int fontDescent = box->renderer()->style(m_firstLine)->fontMetrics().descent(); + LayoutUnit fontAscent = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent(); + LayoutUnit fontDescent = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent(); setAscentAndDescent(ascent, descent, fontAscent, fontDescent, ascentDescentSet); affectsAscent = fontAscent - box->logicalTop() > 0; affectsDescent = fontDescent + box->logicalTop() > 0; @@ -770,13 +803,13 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb setAscentAndDescent(ascent, descent, glyphOverflow->top, glyphOverflow->bottom, ascentDescentSet); affectsAscent = glyphOverflow->top - box->logicalTop() > 0; affectsDescent = glyphOverflow->bottom + box->logicalTop() > 0; - glyphOverflow->top = min(glyphOverflow->top, max(0, glyphOverflow->top - box->renderer()->style(m_firstLine)->fontMetrics().ascent())); - glyphOverflow->bottom = min(glyphOverflow->bottom, max(0, glyphOverflow->bottom - box->renderer()->style(m_firstLine)->fontMetrics().descent())); + glyphOverflow->top = min(glyphOverflow->top, max(0, glyphOverflow->top - box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent())); + glyphOverflow->bottom = min(glyphOverflow->bottom, max(0, glyphOverflow->bottom - box->renderer()->style(isFirstLineStyle())->fontMetrics().descent())); } if (includeMarginForBox(box)) { - int ascentWithMargin = box->renderer()->style(m_firstLine)->fontMetrics().ascent(); - int descentWithMargin = box->renderer()->style(m_firstLine)->fontMetrics().descent(); + LayoutUnit ascentWithMargin = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent(); + LayoutUnit descentWithMargin = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent(); if (box->parent() && !box->renderer()->isText()) { ascentWithMargin += box->boxModelObject()->borderBefore() + box->boxModelObject()->paddingBefore() + box->boxModelObject()->marginBefore(); descentWithMargin += box->boxModelObject()->borderAfter() + box->boxModelObject()->paddingAfter() + box->boxModelObject()->marginAfter(); @@ -800,7 +833,7 @@ LayoutUnit RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositio return 0; // This method determines the vertical position for inline elements. - bool firstLine = m_firstLine; + bool firstLine = isFirstLineStyle(); if (firstLine && !renderer->document()->usesFirstLineRules()) firstLine = false; @@ -812,7 +845,7 @@ LayoutUnit RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositio return verticalPosition; } - int verticalPosition = 0; + LayoutUnit verticalPosition = 0; EVerticalAlign verticalAlign = renderer->style()->verticalAlign(); if (verticalAlign == TOP || verticalAlign == BOTTOM) return 0; @@ -844,7 +877,7 @@ LayoutUnit RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositio } else if (verticalAlign == BASELINE_MIDDLE) verticalPosition += -renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType(), firstLine, lineDirection); else if (verticalAlign == LENGTH) - verticalPosition -= renderer->style()->verticalAlignLength().calcValue(renderer->lineHeight(firstLine, lineDirection)); + verticalPosition -= valueForLength(renderer->style()->verticalAlignLength(), renderer->lineHeight(firstLine, lineDirection), renderer->view()); } // Store the cached value. diff --git a/Source/WebCore/rendering/RootInlineBox.h b/Source/WebCore/rendering/RootInlineBox.h index 901bcff24..49aed00da 100644 --- a/Source/WebCore/rendering/RootInlineBox.h +++ b/Source/WebCore/rendering/RootInlineBox.h @@ -63,6 +63,9 @@ public: LayoutUnit selectionBottom() const; LayoutUnit selectionHeight() const { return max<LayoutUnit>(0, selectionBottom() - selectionTop()); } + LayoutUnit selectionTopAdjustedForPrecedingBlock() const; + LayoutUnit selectionHeightAdjustedForPrecedingBlock() const { return max<LayoutUnit>(0, selectionBottom() - selectionTopAdjustedForPrecedingBlock()); } + int blockDirectionPointInLine() const { return max(lineTop(), selectionTop()); } LayoutUnit alignBoxesInBlockDirection(LayoutUnit heightOfBlock, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&); @@ -83,8 +86,8 @@ public: unsigned lineBreakPos() const { return m_lineBreakPos; } void setLineBreakPos(unsigned p) { m_lineBreakPos = p; } - bool endsWithBreak() const { return m_endsWithBreak; } - void setEndsWithBreak(bool b) { m_endsWithBreak = b; } + using InlineBox::endsWithBreak; + using InlineBox::setEndsWithBreak; void childRemoved(InlineBox* box); @@ -92,7 +95,7 @@ public: void placeEllipsis(const AtomicString& ellipsisStr, bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, InlineBox* markupBox = 0); virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, bool& foundBox); - bool hasEllipsisBox() const { return m_hasEllipsisBoxOrHyphen; } + using InlineBox::hasEllipsisBox; EllipsisBox* ellipsisBox() const; void paintEllipsisBox(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) const; @@ -101,8 +104,8 @@ public: bool isHyphenated() const; - virtual LayoutUnit baselinePosition(FontBaseline baselineType) const { return boxModelObject()->baselinePosition(baselineType, m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); } - virtual LayoutUnit lineHeight() const { return boxModelObject()->lineHeight(m_firstLine, isHorizontal() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); } + virtual LayoutUnit baselinePosition(FontBaseline baselineType) const; + virtual LayoutUnit lineHeight() const; #if PLATFORM(MAC) void addHighlightOverflow(); @@ -112,8 +115,8 @@ public: virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom); - bool hasSelectedChildren() const { return m_hasSelectedChildrenOrCanHaveLeadingExpansion; } - void setHasSelectedChildren(bool hasSelectedChildren) { m_hasSelectedChildrenOrCanHaveLeadingExpansion = hasSelectedChildren; } + using InlineBox::hasSelectedChildren; + using InlineBox::setHasSelectedChildren; virtual RenderObject::SelectionState selectionState(); InlineBox* firstSelectedBox(); @@ -181,11 +184,10 @@ public: virtual const char* boxName() const; #endif private: - void setHasEllipsisBox(bool hasEllipsisBox) { m_hasEllipsisBoxOrHyphen = hasEllipsisBox; } - + LayoutUnit lineSnapAdjustment(LayoutUnit delta = 0) const; - int beforeAnnotationsAdjustment() const; + LayoutUnit beforeAnnotationsAdjustment() const; // This folds into the padding at the end of InlineFlowBox on 64-bit. unsigned m_lineBreakPos; diff --git a/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp b/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp index 167eeb21a..d944eda2f 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp @@ -29,18 +29,24 @@ #include "RenderMathMLBlock.h" -#include "FontSelector.h" #include "GraphicsContext.h" #include "MathMLNames.h" -#include "RenderInline.h" -#include "RenderText.h" + +#if ENABLE(DEBUG_MATH_LAYOUT) +#include "PaintInfo.h" +#endif namespace WebCore { using namespace MathMLNames; RenderMathMLBlock::RenderMathMLBlock(Node* container) - : RenderBlock(container) + : RenderBlock(container) + , m_intrinsicPaddingBefore(0) + , m_intrinsicPaddingAfter(0) + , m_intrinsicPaddingStart(0) + , m_intrinsicPaddingEnd(0) + , m_preferredLogicalHeight(preferredLogicalHeightUnset) { } @@ -49,21 +55,145 @@ bool RenderMathMLBlock::isChildAllowed(RenderObject* child, RenderStyle*) const return child->node() && child->node()->nodeType() == Node::ELEMENT_NODE; } -PassRefPtr<RenderStyle> RenderMathMLBlock::createBlockStyle() +LayoutUnit RenderMathMLBlock::paddingTop() const +{ + LayoutUnit result = computedCSSPaddingTop(); + switch (style()->writingMode()) { + case TopToBottomWritingMode: + return result + m_intrinsicPaddingBefore; + case BottomToTopWritingMode: + return result + m_intrinsicPaddingAfter; + case LeftToRightWritingMode: + case RightToLeftWritingMode: + return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingStart : m_intrinsicPaddingEnd); + } + ASSERT_NOT_REACHED(); + return result; +} + +LayoutUnit RenderMathMLBlock::paddingBottom() const { - RefPtr<RenderStyle> newStyle = RenderStyle::create(); - newStyle->inheritFrom(style()); - newStyle->setDisplay(BLOCK); - return newStyle; + LayoutUnit result = computedCSSPaddingBottom(); + switch (style()->writingMode()) { + case TopToBottomWritingMode: + return result + m_intrinsicPaddingAfter; + case BottomToTopWritingMode: + return result + m_intrinsicPaddingBefore; + case LeftToRightWritingMode: + case RightToLeftWritingMode: + return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingEnd : m_intrinsicPaddingStart); + } + ASSERT_NOT_REACHED(); + return result; +} + +LayoutUnit RenderMathMLBlock::paddingLeft() const +{ + LayoutUnit result = computedCSSPaddingLeft(); + switch (style()->writingMode()) { + case LeftToRightWritingMode: + return result + m_intrinsicPaddingBefore; + case RightToLeftWritingMode: + return result + m_intrinsicPaddingAfter; + case TopToBottomWritingMode: + case BottomToTopWritingMode: + return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingStart : m_intrinsicPaddingEnd); + } + ASSERT_NOT_REACHED(); + return result; +} + +LayoutUnit RenderMathMLBlock::paddingRight() const +{ + LayoutUnit result = computedCSSPaddingRight(); + switch (style()->writingMode()) { + case RightToLeftWritingMode: + return result + m_intrinsicPaddingBefore; + case LeftToRightWritingMode: + return result + m_intrinsicPaddingAfter; + case TopToBottomWritingMode: + case BottomToTopWritingMode: + return result + (style()->isLeftToRightDirection() ? m_intrinsicPaddingEnd : m_intrinsicPaddingStart); + } + ASSERT_NOT_REACHED(); + return result; +} + +LayoutUnit RenderMathMLBlock::paddingBefore() const +{ + return computedCSSPaddingBefore() + m_intrinsicPaddingBefore; +} + +LayoutUnit RenderMathMLBlock::paddingAfter() const +{ + return computedCSSPaddingAfter() + m_intrinsicPaddingAfter; +} + +LayoutUnit RenderMathMLBlock::paddingStart() const +{ + return computedCSSPaddingStart() + m_intrinsicPaddingStart; +} + +LayoutUnit RenderMathMLBlock::paddingEnd() const +{ + return computedCSSPaddingEnd() + m_intrinsicPaddingEnd; +} + +void RenderMathMLBlock::computePreferredLogicalWidths() +{ + ASSERT(preferredLogicalWidthsDirty()); + m_preferredLogicalHeight = preferredLogicalHeightUnset; + RenderBlock::computePreferredLogicalWidths(); +} + +RenderMathMLBlock* RenderMathMLBlock::createAlmostAnonymousBlock(EDisplay display) +{ + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), display); + RenderMathMLBlock* newBlock = new (renderArena()) RenderMathMLBlock(node() /* "almost" anonymous block */); + newBlock->setStyle(newStyle.release()); + return newBlock; +} + +// An arbitrary large value, like RenderBlock.cpp BLOCK_MAX_WIDTH or FixedTableLayout.cpp TABLE_MAX_WIDTH. +static const int cLargeLogicalWidth = 15000; + +void RenderMathMLBlock::computeChildrenPreferredLogicalHeights() +{ + ASSERT(needsLayout()); + + // Ensure a full repaint will happen after layout finishes. + setNeedsLayout(true, MarkOnlyThis); + + LayoutUnit oldAvailableLogicalWidth = availableLogicalWidth(); + setLogicalWidth(cLargeLogicalWidth); + + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + if (!child->isBox()) + continue; + + // Because our width changed, |child| may need layout. + if (child->maxPreferredLogicalWidth() > oldAvailableLogicalWidth) + child->setNeedsLayout(true, MarkOnlyThis); + + RenderMathMLBlock* childMathMLBlock = child->isRenderMathMLBlock() ? toRenderMathMLBlock(child) : 0; + if (childMathMLBlock && !childMathMLBlock->isPreferredLogicalHeightDirty()) + continue; + // Layout our child to compute its preferred logical height. + child->layoutIfNeeded(); + if (childMathMLBlock) + childMathMLBlock->setPreferredLogicalHeight(childMathMLBlock->logicalHeight()); + } } -void RenderMathMLBlock::stretchToHeight(int height) +LayoutUnit RenderMathMLBlock::preferredLogicalHeightAfterSizing(RenderObject* child) { - for (RenderObject* current = firstChild(); current; current = current->nextSibling()) - if (current->isRenderMathMLBlock()) { - RenderMathMLBlock* block = toRenderMathMLBlock(current); - block->stretchToHeight(height); - } + if (child->isRenderMathMLBlock()) + return toRenderMathMLBlock(child)->preferredLogicalHeight(); + if (child->isBox()) { + ASSERT(!child->needsLayout()); + return toRenderBox(child)->logicalHeight(); + } + return child->style()->fontSize(); } #if ENABLE(DEBUG_MATH_LAYOUT) @@ -82,22 +212,22 @@ void RenderMathMLBlock::paint(PaintInfo& info, const LayoutPoint& paintOffset) info.context->setStrokeStyle(SolidStroke); info.context->setStrokeColor(Color(0, 0, 255), ColorSpaceSRGB); - info.context->drawLine(adjustedPaintOffset, LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y())); - info.context->drawLine(LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y()), LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y() + offsetHeight())); - info.context->drawLine(LayoutPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + offsetHeight()), LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y() + offsetHeight())); - info.context->drawLine(adjustedPaintOffset, LayoutPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + offsetHeight())); + info.context->drawLine(adjustedPaintOffset, IntPoint(adjustedPaintOffset.x() + pixelSnappedOffsetWidth(), adjustedPaintOffset.y())); + info.context->drawLine(IntPoint(adjustedPaintOffset.x() + pixelSnappedOffsetWidth(), adjustedPaintOffset.y()), IntPoint(adjustedPaintOffset.x() + pixelSnappedOffsetWidth(), adjustedPaintOffset.y() + pixelSnappedOffsetHeight())); + info.context->drawLine(IntPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + pixelSnappedOffsetHeight()), IntPoint(adjustedPaintOffset.x() + pixelSnappedOffsetWidth(), adjustedPaintOffset.y() + pixelSnappedOffsetHeight())); + info.context->drawLine(adjustedPaintOffset, IntPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + pixelSnappedOffsetHeight())); int topStart = paddingTop(); info.context->setStrokeColor(Color(0, 255, 0), ColorSpaceSRGB); - info.context->drawLine(LayoutPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + topStart), LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y() + topStart)); + info.context->drawLine(IntPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + topStart), IntPoint(adjustedPaintOffset.x() + pixelSnappedOffsetWidth(), adjustedPaintOffset.y() + topStart)); - int baseline = baselinePosition(AlphabeticBaseline, true, HorizontalLine); + int baseline = roundToInt(baselinePosition(AlphabeticBaseline, true, HorizontalLine)); info.context->setStrokeColor(Color(255, 0, 0), ColorSpaceSRGB); - info.context->drawLine(LayoutPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + baseline), LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y() + baseline)); + info.context->drawLine(IntPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + baseline), IntPoint(adjustedPaintOffset.x() + pixelSnappedOffsetWidth(), adjustedPaintOffset.y() + baseline)); } #endif // ENABLE(DEBUG_MATH_LAYOUT) diff --git a/Source/WebCore/rendering/mathml/RenderMathMLBlock.h b/Source/WebCore/rendering/mathml/RenderMathMLBlock.h index 5d4d780ed..634d0a6dc 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLBlock.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLBlock.h @@ -54,12 +54,35 @@ public: // FIXME: We don't yet handle all the cases in the MathML spec. See // https://bugs.webkit.org/show_bug.cgi?id=78617. virtual RenderMathMLOperator* unembellishedOperator() { return 0; } - virtual void stretchToHeight(int height); + virtual LayoutUnit paddingTop() const OVERRIDE; + virtual LayoutUnit paddingBottom() const OVERRIDE; + virtual LayoutUnit paddingLeft() const OVERRIDE; + virtual LayoutUnit paddingRight() const OVERRIDE; + virtual LayoutUnit paddingBefore() const OVERRIDE; + virtual LayoutUnit paddingAfter() const OVERRIDE; + virtual LayoutUnit paddingStart() const OVERRIDE; + virtual LayoutUnit paddingEnd() const OVERRIDE; + + // A MathML element's preferred logical widths often depend on its children's preferred heights, not just their widths. + // This is due to operator stretching and other layout fine tuning. We define an element's preferred height to be its + // actual height after layout inside a very wide parent. + bool isPreferredLogicalHeightDirty() const { return preferredLogicalWidthsDirty() || m_preferredLogicalHeight < 0; } + // The caller must ensure !isPreferredLogicalHeightDirty(). + LayoutUnit preferredLogicalHeight() const { ASSERT(!isPreferredLogicalHeightDirty()); return m_preferredLogicalHeight; } + static const int preferredLogicalHeightUnset = -1; + void setPreferredLogicalHeight(LayoutUnit logicalHeight) { m_preferredLogicalHeight = logicalHeight; } + // computePreferredLogicalWidths() in derived classes must ensure m_preferredLogicalHeight is set to < 0 or its correct value. + virtual void computePreferredLogicalWidths() OVERRIDE; + #if ENABLE(DEBUG_MATH_LAYOUT) virtual void paint(PaintInfo&, const LayoutPoint&); #endif + // Create a new RenderBlock, with a new style inheriting from this->style(). + // FIXME: Create a true anonymous block, like RenderBlock::createAnonymousBlock(). + RenderMathMLBlock* createAlmostAnonymousBlock(EDisplay = BLOCK); + protected: static LayoutUnit getBoxModelObjectHeight(const RenderObject* object) { @@ -79,10 +102,23 @@ protected: return 0; } - virtual PassRefPtr<RenderStyle> createBlockStyle(); private: virtual const char* renderName() const { return isAnonymous() ? "RenderMathMLBlock (anonymous)" : "RenderMathMLBlock"; } + +protected: + // Set our logical width to a large value, and compute our children's preferred logical heights. + void computeChildrenPreferredLogicalHeights(); + // This can only be called after children have been sized by computeChildrenPreferredLogicalHeights(). + static LayoutUnit preferredLogicalHeightAfterSizing(RenderObject* child); + + int m_intrinsicPaddingBefore; + int m_intrinsicPaddingAfter; + int m_intrinsicPaddingStart; + int m_intrinsicPaddingEnd; + + // m_preferredLogicalHeight is dirty if it's < 0 or preferredLogicalWidthsDirty(). + LayoutUnit m_preferredLogicalHeight; }; inline RenderMathMLBlock* toRenderMathMLBlock(RenderObject* object) diff --git a/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp b/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp index c2f67ea93..4297dd7ff 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp @@ -131,11 +131,7 @@ void RenderMathMLFenced::addChild(RenderObject* child, RenderObject*) if (child->isBlockFlow() && child->style()->display() != INLINE_BLOCK) { // Block objects wrapper. - RenderBlock* block = new (renderArena()) RenderBlock(node()); - RefPtr<RenderStyle> newStyle = RenderStyle::create(); - newStyle->inheritFrom(style()); - newStyle->setDisplay(INLINE_BLOCK); - block->setStyle(newStyle.release()); + RenderBlock* block = createAlmostAnonymousBlock(INLINE_BLOCK); RenderBlock::addChild(block, lastChild()); block->addChild(child); diff --git a/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp b/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp index dd59bb998..296548a2e 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp @@ -61,26 +61,26 @@ void RenderMathMLFraction::updateFromElement() Element* fraction = static_cast<Element*>(node()); - RenderObject* numerator = firstChild(); + RenderObject* numeratorWrapper = firstChild(); String nalign = fraction->getAttribute(MathMLNames::numalignAttr); if (equalIgnoringCase(nalign, "left")) - numerator->style()->setTextAlign(LEFT); + numeratorWrapper->style()->setTextAlign(LEFT); else if (equalIgnoringCase(nalign, "right")) - numerator->style()->setTextAlign(RIGHT); + numeratorWrapper->style()->setTextAlign(RIGHT); else - numerator->style()->setTextAlign(CENTER); + numeratorWrapper->style()->setTextAlign(CENTER); - RenderObject* denominator = numerator->nextSibling(); - if (!denominator) + RenderObject* denominatorWrapper = numeratorWrapper->nextSibling(); + if (!denominatorWrapper) return; String dalign = fraction->getAttribute(MathMLNames::denomalignAttr); if (equalIgnoringCase(dalign, "left")) - denominator->style()->setTextAlign(LEFT); + denominatorWrapper->style()->setTextAlign(LEFT); else if (equalIgnoringCase(dalign, "right")) - denominator->style()->setTextAlign(RIGHT); + denominatorWrapper->style()->setTextAlign(RIGHT); else - denominator->style()->setTextAlign(CENTER); + denominatorWrapper->style()->setTextAlign(CENTER); // FIXME: parse units String thickness = fraction->getAttribute(MathMLNames::linethicknessAttr); @@ -100,20 +100,18 @@ void RenderMathMLFraction::updateFromElement() void RenderMathMLFraction::addChild(RenderObject* child, RenderObject* beforeChild) { - RenderBlock* row = new (renderArena()) RenderMathMLBlock(node()); - RefPtr<RenderStyle> rowStyle = createBlockStyle(); + RenderBlock* row = createAlmostAnonymousBlock(); - rowStyle->setTextAlign(CENTER); - Length pad(static_cast<int>(rowStyle->fontSize() * gHorizontalPad), Fixed); - rowStyle->setPaddingLeft(pad); - rowStyle->setPaddingRight(pad); + row->style()->setTextAlign(CENTER); + Length pad(static_cast<int>(style()->fontSize() * gHorizontalPad), Fixed); + row->style()->setPaddingLeft(pad); + row->style()->setPaddingRight(pad); // Only add padding for rows as denominators bool isNumerator = isEmpty(); if (!isNumerator) - rowStyle->setPaddingTop(Length(2, Fixed)); + row->style()->setPaddingTop(Length(2, Fixed)); - row->setStyle(rowStyle.release()); RenderBlock::addChild(row, beforeChild); row->addChild(child); updateFromElement(); @@ -139,7 +137,6 @@ void RenderMathMLFraction::layout() m_lineThickness *= ceilf(gFractionBarWidth * style()->fontSize()); RenderBlock::layout(); - } void RenderMathMLFraction::paint(PaintInfo& info, const LayoutPoint& paintOffset) @@ -151,17 +148,18 @@ void RenderMathMLFraction::paint(PaintInfo& info, const LayoutPoint& paintOffset if (!firstChild() ||!m_lineThickness) return; - LayoutUnit verticalOffset = 0; + int verticalOffset = 0; // The children are always RenderMathMLBlock instances if (firstChild()->isRenderMathMLBlock()) { int adjustForThickness = m_lineThickness > 1 ? int(m_lineThickness / 2) : 1; if (int(m_lineThickness) % 2 == 1) adjustForThickness++; + // FIXME: This is numeratorWrapper, not numerator. RenderMathMLBlock* numerator = toRenderMathMLBlock(firstChild()); if (numerator->isRenderMathMLRow()) - verticalOffset = numerator->offsetHeight() + adjustForThickness; + verticalOffset = numerator->pixelSnappedOffsetHeight() + adjustForThickness; else - verticalOffset = numerator->offsetHeight(); + verticalOffset = numerator->pixelSnappedOffsetHeight(); } IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location()); @@ -173,20 +171,20 @@ void RenderMathMLFraction::paint(PaintInfo& info, const LayoutPoint& paintOffset info.context->setStrokeStyle(SolidStroke); info.context->setStrokeColor(style()->visitedDependentColor(CSSPropertyColor), ColorSpaceSRGB); - info.context->drawLine(adjustedPaintOffset, IntPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y())); + info.context->drawLine(adjustedPaintOffset, IntPoint(adjustedPaintOffset.x() + pixelSnappedOffsetWidth(), adjustedPaintOffset.y())); } LayoutUnit RenderMathMLFraction::baselinePosition(FontBaseline, bool firstLine, LineDirectionMode lineDirection, LinePositionMode linePositionMode) const { if (firstChild() && firstChild()->isRenderMathMLBlock()) { - RenderMathMLBlock* numerator = toRenderMathMLBlock(firstChild()); + RenderMathMLBlock* numeratorWrapper = toRenderMathMLBlock(firstChild()); RenderStyle* refStyle = style(); if (previousSibling()) refStyle = previousSibling()->style(); else if (nextSibling()) refStyle = nextSibling()->style(); int shift = int(ceil((refStyle->fontMetrics().xHeight() + 1) / 2)); - return numerator->offsetHeight() + shift; + return numeratorWrapper->pixelSnappedOffsetHeight() + shift; } return RenderBlock::baselinePosition(AlphabeticBaseline, firstLine, lineDirection, linePositionMode); } diff --git a/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp b/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp index ad11d8bac..50f02be59 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp @@ -62,20 +62,23 @@ static const float gOperatorExpansion = 1.2f; void RenderMathMLOperator::stretchToHeight(int height) { - if (height == m_stretchHeight) + height *= gOperatorExpansion; + if (m_stretchHeight == height) return; - m_stretchHeight = static_cast<int>(height * gOperatorExpansion); + m_stretchHeight = height; - updateBoxModelInfoFromStyle(); - setNeedsLayout(true); + updateFromElement(); } -void RenderMathMLOperator::layout() +void RenderMathMLOperator::computePreferredLogicalWidths() { - // FIXME: This probably shouldn't be called here but when the operator - // isn't stretched (e.g. outside of a mrow), it needs to be called somehow - updateFromElement(); - RenderBlock::layout(); + ASSERT(preferredLogicalWidthsDirty()); + + // Check for an uninitialized operator. + if (!firstChild()) + updateFromElement(); + + RenderMathMLBlock::computePreferredLogicalWidths(); } // This is a table of stretchy characters. @@ -113,6 +116,12 @@ static struct StretchyCharacter { // All of these settings are represented in the constants below. // FIXME: use fractions of style()->fontSize() for proper zooming/resizing. +// FIXME: None of this should be hard-coded. Not only does this cause problems +// with zooming, but it also sets up assumptions that break when a font contains +// a glyph that is smaller than expected. For example, the STIX vertical bar +// glyph is smaller than expected, and glyphHeightForCharacter() and +// lineHeightForCharacter() were added to make smaller glyphs work in this system. +// Really, the system should just be reconsidered. static const int gGlyphFontSize = 14; static const int gGlyphLineHeight = 11; static const int gMinimumStretchHeight = 24; @@ -122,6 +131,25 @@ static const int gMiddleGlyphTopAdjust = -1; static const int gBottomGlyphTopAdjust = -3; static const float gMinimumRatioForStretch = 0.10f; +// This should always be called instead of accessing gGlyphHeight directly. +int RenderMathMLOperator::glyphHeightForCharacter(UChar character) +{ + GlyphData data = style()->font().glyphDataForCharacter(character, false); + FloatRect glyphBounds = data.fontData->boundsForGlyph(data.glyph); + if (glyphBounds.height() && glyphBounds.height() < gGlyphHeight) + return glyphBounds.height(); + return gGlyphHeight; +} + +// This should always be called instead of accessing gGlyphLineHeight directly. +int RenderMathMLOperator::lineHeightForCharacter(UChar character) +{ + int glyphHeight = glyphHeightForCharacter(character); + if (glyphHeight < gGlyphHeight) + return (glyphHeight - 1) > 0 ? glyphHeight - 1 : 1; + return gGlyphLineHeight; +} + void RenderMathMLOperator::updateFromElement() { RenderObject* savedRenderer = node()->renderer(); @@ -190,12 +218,12 @@ void RenderMathMLOperator::updateFromElement() // font size to adjust the glyph size. int currentFontSize = style()->fontSize(); if (!stretchDisabled && isStretchy && m_stretchHeight > 0 && m_stretchHeight <= gMinimumStretchHeight && m_stretchHeight > currentFontSize) { - FontDescription desc; + FontDescription desc = style()->fontDescription(); desc.setIsAbsoluteSize(true); desc.setSpecifiedSize(m_stretchHeight); desc.setComputedSize(m_stretchHeight); newStyle->setFontDescription(desc); - newStyle->font().update(newStyle->font().fontSelector()); + newStyle->font().update(style()->font().fontSelector()); } container->setStyle(newStyle.release()); @@ -218,87 +246,96 @@ void RenderMathMLOperator::updateFromElement() } else { // Build stretchable characters as a stack of glyphs. m_isStacked = true; + + int extensionGlyphLineHeight = lineHeightForCharacter(stretchyCharacters[index].extensionGlyph); + int topGlyphLineHeight = lineHeightForCharacter(stretchyCharacters[index].topGlyph); + int bottomGlyphLineHeight = lineHeightForCharacter(stretchyCharacters[index].bottomGlyph); if (stretchyCharacters[index].middleGlyph) { // We have a middle glyph (e.g. a curly bracket) that requires special processing. - int half = (m_stretchHeight - gGlyphHeight) / 2; - if (half <= gGlyphHeight) { + int glyphHeight = glyphHeightForCharacter(stretchyCharacters[index].middleGlyph); + int middleGlyphLineHeight = lineHeightForCharacter(stretchyCharacters[index].middleGlyph); + int half = (m_stretchHeight - glyphHeight) / 2; + if (half <= glyphHeight) { // We only have enough space for a single middle glyph. - createGlyph(stretchyCharacters[index].topGlyph, half, gTopGlyphTopAdjust); - createGlyph(stretchyCharacters[index].middleGlyph, gGlyphHeight, gMiddleGlyphTopAdjust); - createGlyph(stretchyCharacters[index].bottomGlyph, 0, gBottomGlyphTopAdjust); + createGlyph(stretchyCharacters[index].topGlyph, topGlyphLineHeight, half, gTopGlyphTopAdjust); + createGlyph(stretchyCharacters[index].middleGlyph, middleGlyphLineHeight, glyphHeight, gMiddleGlyphTopAdjust); + createGlyph(stretchyCharacters[index].bottomGlyph, bottomGlyphLineHeight, 0, gBottomGlyphTopAdjust); } else { // We have to extend both the top and bottom to the middle. - createGlyph(stretchyCharacters[index].topGlyph, gGlyphHeight, gTopGlyphTopAdjust); - int remaining = half - gGlyphHeight; + createGlyph(stretchyCharacters[index].topGlyph, topGlyphLineHeight, glyphHeight, gTopGlyphTopAdjust); + int remaining = half - glyphHeight; while (remaining > 0) { - if (remaining < gGlyphHeight) { - createGlyph(stretchyCharacters[index].extensionGlyph, remaining); + if (remaining < glyphHeight) { + createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, remaining); remaining = 0; } else { - createGlyph(stretchyCharacters[index].extensionGlyph, gGlyphHeight); - remaining -= gGlyphHeight; + createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, glyphHeight); + remaining -= glyphHeight; } } // The middle glyph in the stack. - createGlyph(stretchyCharacters[index].middleGlyph, gGlyphHeight, gMiddleGlyphTopAdjust); + createGlyph(stretchyCharacters[index].middleGlyph, middleGlyphLineHeight, glyphHeight, gMiddleGlyphTopAdjust); // The remaining is the top half minus the middle glyph height. - remaining = half - gGlyphHeight; + remaining = half - glyphHeight; // We need to make sure we have the full height in case the height is odd. if (m_stretchHeight % 2 == 1) remaining++; // Extend to the bottom glyph. while (remaining > 0) { - if (remaining < gGlyphHeight) { - createGlyph(stretchyCharacters[index].extensionGlyph, remaining); + if (remaining < glyphHeight) { + createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, remaining); remaining = 0; } else { - createGlyph(stretchyCharacters[index].extensionGlyph, gGlyphHeight); - remaining -= gGlyphHeight; + createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, glyphHeight); + remaining -= glyphHeight; } } // The bottom glyph in the stack. - createGlyph(stretchyCharacters[index].bottomGlyph, 0, gBottomGlyphTopAdjust); + createGlyph(stretchyCharacters[index].bottomGlyph, bottomGlyphLineHeight, 0, gBottomGlyphTopAdjust); } } else { // We do not have a middle glyph and so we just extend from the top to the bottom glyph. - int remaining = m_stretchHeight - 2 * gGlyphHeight; - createGlyph(stretchyCharacters[index].topGlyph, gGlyphHeight, gTopGlyphTopAdjust); + int glyphHeight = glyphHeightForCharacter(stretchyCharacters[index].extensionGlyph); + int remaining = m_stretchHeight - 2 * glyphHeight; + createGlyph(stretchyCharacters[index].topGlyph, topGlyphLineHeight, glyphHeight, gTopGlyphTopAdjust); while (remaining > 0) { - if (remaining < gGlyphHeight) { - createGlyph(stretchyCharacters[index].extensionGlyph, remaining); + if (remaining < glyphHeight) { + createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, remaining); remaining = 0; } else { - createGlyph(stretchyCharacters[index].extensionGlyph, gGlyphHeight); - remaining -= gGlyphHeight; + createGlyph(stretchyCharacters[index].extensionGlyph, extensionGlyphLineHeight, glyphHeight); + remaining -= glyphHeight; } } - createGlyph(stretchyCharacters[index].bottomGlyph, 0, gBottomGlyphTopAdjust); + createGlyph(stretchyCharacters[index].bottomGlyph, bottomGlyphLineHeight, 0, gBottomGlyphTopAdjust); } } + + setNeedsLayoutAndPrefWidthsRecalc(); } -PassRefPtr<RenderStyle> RenderMathMLOperator::createStackableStyle(int size, int topRelative) +PassRefPtr<RenderStyle> RenderMathMLOperator::createStackableStyle(int lineHeight, int maxHeightForRenderer, int topRelative) { RefPtr<RenderStyle> newStyle = RenderStyle::create(); newStyle->inheritFrom(style()); newStyle->setDisplay(BLOCK); - FontDescription desc; + FontDescription desc = style()->fontDescription(); desc.setIsAbsoluteSize(true); desc.setSpecifiedSize(gGlyphFontSize); desc.setComputedSize(gGlyphFontSize); newStyle->setFontDescription(desc); - newStyle->font().update(newStyle->font().fontSelector()); - newStyle->setLineHeight(Length(gGlyphLineHeight, Fixed)); + newStyle->font().update(style()->font().fontSelector()); + newStyle->setLineHeight(Length(lineHeight, Fixed)); newStyle->setVerticalAlign(TOP); - if (size > 0) - newStyle->setMaxHeight(Length(size, Fixed)); + if (maxHeightForRenderer > 0) + newStyle->setMaxHeight(Length(maxHeightForRenderer, Fixed)); newStyle->setOverflowY(OHIDDEN); newStyle->setOverflowX(OHIDDEN); @@ -310,10 +347,10 @@ PassRefPtr<RenderStyle> RenderMathMLOperator::createStackableStyle(int size, int return newStyle.release(); } -RenderBlock* RenderMathMLOperator::createGlyph(UChar glyph, int size, int charRelative, int topRelative) +RenderBlock* RenderMathMLOperator::createGlyph(UChar glyph, int lineHeight, int maxHeightForRenderer, int charRelative, int topRelative) { RenderBlock* container = new (renderArena()) RenderMathMLBlock(node()); - container->setStyle(createStackableStyle(size, topRelative)); + container->setStyle(createStackableStyle(lineHeight, maxHeightForRenderer, topRelative)); addChild(container); RenderBlock* parent = container; if (charRelative) { diff --git a/Source/WebCore/rendering/mathml/RenderMathMLOperator.h b/Source/WebCore/rendering/mathml/RenderMathMLOperator.h index 42708724a..5adab8fd1 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLOperator.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLOperator.h @@ -38,20 +38,26 @@ public: RenderMathMLOperator(Element*); RenderMathMLOperator(Node*, UChar operatorChar); virtual bool isRenderMathMLOperator() const { return true; } - virtual RenderMathMLOperator* unembellishedOperator() { return this; } - virtual void stretchToHeight(int pixelHeight); - virtual void updateFromElement(); + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + virtual void updateFromElement() OVERRIDE; + + virtual RenderMathMLOperator* unembellishedOperator() OVERRIDE { return this; } + void stretchToHeight(int pixelHeight); + virtual LayoutUnit baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; protected: - virtual void layout(); - virtual PassRefPtr<RenderStyle> createStackableStyle(int size, int topRelative); - virtual RenderBlock* createGlyph(UChar glyph, int size = 0, int charRelative = 0, int topRelative = 0); + virtual void computePreferredLogicalWidths() OVERRIDE; + PassRefPtr<RenderStyle> createStackableStyle(int lineHeight, int maxHeightForRenderer, int topRelative); + RenderBlock* createGlyph(UChar glyph, int lineHeight, int maxHeightForRenderer = 0, int charRelative = 0, int topRelative = 0); private: virtual const char* renderName() const { return isAnonymous() ? "RenderMathMLOperator (anonymous)" : "RenderMathMLOperator"; } + int glyphHeightForCharacter(UChar); + int lineHeightForCharacter(UChar); + int m_stretchHeight; bool m_isStacked; UChar m_operator; diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp b/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp index 07e8ff911..e6d5165a9 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp @@ -34,122 +34,83 @@ #include "MathMLNames.h" #include "PaintInfo.h" +using namespace std; + namespace WebCore { using namespace MathMLNames; -// Left margin of the radical (px) -const int gRadicalLeftMargin = 3; -// Bottom padding of the radical (px) -const int gRadicalBasePad = 3; -// Threshold above which the radical shape is modified to look nice with big bases (%) -const float gThresholdBaseHeight = 1.5f; -// Radical width (%) -const float gRadicalWidth = 0.75f; -// Horizontal position of the bottom point of the radical (%) -const float gRadicalBottomPointXPos= 0.5f; -// Horizontal position of the top left point of the radical (%) -const float gRadicalTopLeftPointXPos = 0.8f; -// Vertical position of the top left point of the radical (%) -const float gRadicalTopLeftPointYPos = 0.625f; -// Vertical shift of the left end point of the radical (%) -const float gRadicalLeftEndYShift = 0.05f; -// Root padding around the base (%) -const float gRootPadding = 0.2f; -// Additional bottom root padding (%) -const float gRootBottomPadding = 0.2f; - -// Radical line thickness (%) -const float gRadicalLineThickness = 0.02f; -// Radical thick line thickness (%) -const float gRadicalThickLineThickness = 0.1f; +// FIXME: This whole file should be changed to work with various writing modes. See https://bugs.webkit.org/show_bug.cgi?id=48951. + +// Threshold above which the radical shape is modified to look nice with big bases (em) +const float gThresholdBaseHeightEms = 1.5f; +// Normal width of the front of the radical sign, before the base & overbar (em) +const float gFrontWidthEms = 0.75f; +// Gap between the base and overbar (em) +const float gSpaceAboveEms = 0.2f; +// Horizontal position of the bottom point of the radical (* frontWidth) +const float gRadicalBottomPointXFront = 0.5f; +// Lower the radical sign's bottom point (px) +const int gRadicalBottomPointLower = 3; +// Horizontal position of the top left point of the radical "dip" (* frontWidth) +const float gRadicalDipLeftPointXFront = 0.8f; +// Vertical position of the top left point of the radical "dip" (* baseHeight) +const float gRadicalDipLeftPointYPos = 0.625f; +// Vertical shift of the left end point of the radical (em) +const float gRadicalLeftEndYShiftEms = 0.05f; +// Additional bottom root padding if baseHeight > threshold (em) +const float gBigRootBottomPaddingEms = 0.2f; + +// Radical line thickness (em) +const float gRadicalLineThicknessEms = 0.02f; +// Radical thick line thickness (em) +const float gRadicalThickLineThicknessEms = 0.1f; RenderMathMLRoot::RenderMathMLRoot(Element* element) : RenderMathMLBlock(element) { } -void RenderMathMLRoot::addChild(RenderObject* child, RenderObject* ) +RenderBoxModelObject* RenderMathMLRoot::index() const { - if (isEmpty()) { - // Add a block for the index - RenderBlock* block = new (renderArena()) RenderBlock(node()); - RefPtr<RenderStyle> indexStyle = createBlockStyle(); - indexStyle->setDisplay(INLINE_BLOCK); - block->setStyle(indexStyle.release()); - RenderBlock::addChild(block); - - // FIXME: the wrapping does not seem to be needed anymore. - // this is the base, so wrap it so we can pad it - block = new (renderArena()) RenderBlock(node()); - RefPtr<RenderStyle> baseStyle = createBlockStyle(); - baseStyle->setDisplay(INLINE_BLOCK); - baseStyle->setPaddingLeft(Length(5 * gRadicalWidth , Percent)); - block->setStyle(baseStyle.release()); - RenderBlock::addChild(block); - block->addChild(child); - } else { - // always add to the index - firstChild()->addChild(child); - } + if (!firstChild()) + return 0; + RenderObject* index = firstChild()->nextSibling(); + if (!index || !index->isBoxModelObject()) + return 0; + return toRenderBoxModelObject(index); } - + void RenderMathMLRoot::paint(PaintInfo& info, const LayoutPoint& paintOffset) { RenderMathMLBlock::paint(info, paintOffset); if (info.context->paintingDisabled()) return; - - if (!firstChild() || !lastChild()) - return; - - IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location()); - - RenderBoxModelObject* indexBox = toRenderBoxModelObject(lastChild()); - LayoutUnit maxHeight = indexBox->offsetHeight(); - // default to the font size in pixels if we're empty - if (!maxHeight) - maxHeight = style()->fontSize(); - LayoutUnit width = indexBox->offsetWidth(); + if (!index()) + return; - LayoutUnit indexWidth = 0; - RenderObject* current = firstChild(); - while (current != lastChild()) { - if (current->isBoxModelObject()) { - RenderBoxModelObject* box = toRenderBoxModelObject(current); - indexWidth += box->offsetWidth(); - } - current = current->nextSibling(); - } + IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + computedCSSContentBoxRect().location()); - int frontWidth = static_cast<int>(style()->fontSize() * gRadicalWidth); - int topStartShift = 0; - // Base height above which the shape of the root changes - int thresholdHeight = static_cast<int>(gThresholdBaseHeight * style()->fontSize()); + int baseHeight = roundToInt(getBoxModelObjectHeight(firstChild())); - if (maxHeight > thresholdHeight && thresholdHeight) { - float shift = (maxHeight - thresholdHeight) / static_cast<float>(thresholdHeight); - if (shift > 1.) - shift = 1.0f; - topStartShift = static_cast<int>(gRadicalBottomPointXPos * frontWidth * shift); - } + int overbarWidth = roundToInt(getBoxModelObjectWidth(firstChild())) + m_overbarLeftPointShift; + int indexWidth = index()->pixelSnappedOffsetWidth(); + int frontWidth = static_cast<int>(roundf(gFrontWidthEms * style()->fontSize())); + int startX = adjustedPaintOffset.x() + indexWidth + m_overbarLeftPointShift; - width += topStartShift; + int rootPad = static_cast<int>(roundf(gSpaceAboveEms * style()->fontSize())); + adjustedPaintOffset.setY(adjustedPaintOffset.y() + m_intrinsicPaddingBefore - rootPad); - int rootPad = static_cast<int>(gRootPadding * style()->fontSize()); - LayoutUnit start = adjustedPaintOffset.x() + indexWidth + gRadicalLeftMargin + style()->paddingLeft().value() - rootPad; - adjustedPaintOffset.setY(adjustedPaintOffset.y() + style()->paddingTop().value() - rootPad); - - FloatPoint topStart(start - topStartShift, adjustedPaintOffset.y()); - FloatPoint bottomLeft(start - gRadicalBottomPointXPos * frontWidth , adjustedPaintOffset.y() + maxHeight + gRadicalBasePad); - FloatPoint topLeft(start - gRadicalTopLeftPointXPos * frontWidth , adjustedPaintOffset.y() + gRadicalTopLeftPointYPos * maxHeight); - FloatPoint leftEnd(start - frontWidth , topLeft.y() + gRadicalLeftEndYShift * style()->fontSize()); + FloatPoint overbarLeftPoint(startX - m_overbarLeftPointShift, adjustedPaintOffset.y()); + FloatPoint bottomPoint(startX - gRadicalBottomPointXFront * frontWidth, adjustedPaintOffset.y() + baseHeight + gRadicalBottomPointLower); + FloatPoint dipLeftPoint(startX - gRadicalDipLeftPointXFront * frontWidth, adjustedPaintOffset.y() + gRadicalDipLeftPointYPos * baseHeight); + FloatPoint leftEnd(startX - frontWidth, dipLeftPoint.y() + gRadicalLeftEndYShiftEms * style()->fontSize()); GraphicsContextStateSaver stateSaver(*info.context); - info.context->setStrokeThickness(gRadicalLineThickness * style()->fontSize()); + info.context->setStrokeThickness(gRadicalLineThicknessEms * style()->fontSize()); info.context->setStrokeStyle(SolidStroke); info.context->setStrokeColor(style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB); info.context->setLineJoin(MiterJoin); @@ -157,13 +118,13 @@ void RenderMathMLRoot::paint(PaintInfo& info, const LayoutPoint& paintOffset) Path root; - root.moveTo(FloatPoint(topStart.x() + width, adjustedPaintOffset.y())); + root.moveTo(FloatPoint(overbarLeftPoint.x() + overbarWidth, adjustedPaintOffset.y())); // draw top - root.addLineTo(topStart); + root.addLineTo(overbarLeftPoint); // draw from top left corner to bottom point of radical - root.addLineTo(bottomLeft); - // draw from bottom point to top of left part of radical base "pocket" - root.addLineTo(topLeft); + root.addLineTo(bottomPoint); + // draw from bottom point to top of left part of radical base "dip" + root.addLineTo(dipLeftPoint); // draw to end root.addLineTo(leftEnd); @@ -174,21 +135,21 @@ void RenderMathMLRoot::paint(PaintInfo& info, const LayoutPoint& paintOffset) // Build a mask to draw the thick part of the root. Path mask; - mask.moveTo(topStart); - mask.addLineTo(bottomLeft); - mask.addLineTo(topLeft); - mask.addLineTo(FloatPoint(2 * topLeft.x() - leftEnd.x(), 2 * topLeft.y() - leftEnd.y())); + mask.moveTo(overbarLeftPoint); + mask.addLineTo(bottomPoint); + mask.addLineTo(dipLeftPoint); + mask.addLineTo(FloatPoint(2 * dipLeftPoint.x() - leftEnd.x(), 2 * dipLeftPoint.y() - leftEnd.y())); info.context->clip(mask); // Draw the thick part of the root. - info.context->setStrokeThickness(gRadicalThickLineThickness * style()->fontSize()); + info.context->setStrokeThickness(gRadicalThickLineThicknessEms * style()->fontSize()); info.context->setLineCap(SquareCap); Path line; - line.moveTo(bottomLeft); - line.addLineTo(topLeft); - + line.moveTo(bottomPoint); + line.addLineTo(dipLeftPoint); + info.context->strokePath(line); } @@ -196,60 +157,42 @@ void RenderMathMLRoot::layout() { RenderBlock::layout(); - if (!firstChild() || !lastChild()) + if (!index()) return; - LayoutUnit maxHeight = toRenderBoxModelObject(lastChild())->offsetHeight(); - - RenderObject* current = lastChild()->firstChild(); - if (current) - current->style()->setVerticalAlign(BASELINE); - - if (!maxHeight) - maxHeight = style()->fontSize(); + int baseHeight = roundToInt(getBoxModelObjectHeight(firstChild())); // Base height above which the shape of the root changes - LayoutUnit thresholdHeight = static_cast<LayoutUnit>(gThresholdBaseHeight * style()->fontSize()); - LayoutUnit topStartShift = 0; - - if (maxHeight > thresholdHeight && thresholdHeight) { - float shift = (maxHeight - thresholdHeight) / static_cast<float>(thresholdHeight); - if (shift > 1.) - shift = 1.0f; - LayoutUnit frontWidth = static_cast<LayoutUnit>(style()->fontSize() * gRadicalWidth); - topStartShift = static_cast<LayoutUnit>(gRadicalBottomPointXPos * frontWidth * shift); - - style()->setPaddingBottom(Length(static_cast<LayoutUnit>(gRootBottomPadding * style()->fontSize()), Fixed)); + float thresholdHeight = gThresholdBaseHeightEms * style()->fontSize(); + if (baseHeight > thresholdHeight && thresholdHeight) { + float shift = min<float>((baseHeight - thresholdHeight) / thresholdHeight, 1.0f); + int frontWidth = static_cast<int>(roundf(gFrontWidthEms * style()->fontSize())); + m_overbarLeftPointShift = static_cast<int>(shift * gRadicalBottomPointXFront * frontWidth); + m_intrinsicPaddingAfter = static_cast<int>(roundf(gBigRootBottomPaddingEms * style()->fontSize())); + } else { + m_overbarLeftPointShift = 0; + m_intrinsicPaddingAfter = 0; } - // Positioning of the index - RenderObject* possibleIndex = firstChild()->firstChild(); - while (possibleIndex && !possibleIndex->isBoxModelObject()) - possibleIndex = possibleIndex->nextSibling(); - RenderBoxModelObject* indexBox = toRenderBoxModelObject(possibleIndex); - if (!indexBox) - return; + RenderBoxModelObject* index = this->index(); - LayoutUnit indexShift = indexBox->offsetWidth() + topStartShift; - LayoutUnit radicalHeight = static_cast<LayoutUnit>((1 - gRadicalTopLeftPointYPos) * maxHeight); - LayoutUnit rootMarginTop = radicalHeight + style()->paddingBottom().value() + indexBox->offsetHeight() - - (maxHeight + static_cast<LayoutUnit>(gRootPadding * style()->fontSize())); + m_intrinsicPaddingStart = index->pixelSnappedOffsetWidth() + m_overbarLeftPointShift; - style()->setPaddingLeft(Length(indexShift, Fixed)); - if (rootMarginTop > 0) - style()->setPaddingTop(Length(rootMarginTop + static_cast<LayoutUnit>(gRootPadding * style()->fontSize()), Fixed)); + int rootPad = static_cast<int>(roundf(gSpaceAboveEms * style()->fontSize())); + int partDipHeight = static_cast<int>(roundf((1 - gRadicalDipLeftPointYPos) * baseHeight)); + int rootExtraTop = partDipHeight + index->pixelSnappedOffsetHeight() - (baseHeight + rootPad); + m_intrinsicPaddingBefore = rootPad + max(rootExtraTop, 0); - setNeedsLayout(true); - setPreferredLogicalWidthsDirty(true, false); + setNeedsLayout(true, MarkOnlyThis); + setPreferredLogicalWidthsDirty(true, MarkOnlyThis); // FIXME: Can this really be right? + // FIXME: Preferred logical widths are currently wrong the first time through, relying on layout() to set m_intrinsicPaddingStart. RenderBlock::layout(); - - indexBox->style()->setBottom(Length(radicalHeight + style()->paddingBottom().value(), Fixed)); - - // Now that we've potentially changed its position, we need layout the index again. - indexBox->setNeedsLayout(true); - indexBox->layout(); -} + // |index| should be a RenderBlock here, unless the user has overriden its { position: absolute }. + if (rootExtraTop < 0 && index->isBox()) + toRenderBox(index)->setLogicalTop(-rootExtraTop); +} + } #endif // ENABLE(MATHML) diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRoot.h b/Source/WebCore/rendering/mathml/RenderMathMLRoot.h index 19b2ec6ec..65ec82dc7 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLRoot.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLRoot.h @@ -32,16 +32,23 @@ namespace WebCore { +// Render base^(1/index), using radical notation. class RenderMathMLRoot : public RenderMathMLBlock { public: RenderMathMLRoot(Element*); - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); - virtual void paint(PaintInfo&, const LayoutPoint&); + protected: - virtual void layout(); + virtual void layout() OVERRIDE; + + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; private: virtual const char* renderName() const { return "RenderMathMLRoot"; } + + // This may return 0 for a non-MathML index (which won't occur in valid MathML). + RenderBoxModelObject* index() const; + + int m_overbarLeftPointShift; }; } diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp b/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp index 203d194de..347e96cf0 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp @@ -36,53 +36,64 @@ namespace WebCore { using namespace MathMLNames; -RenderMathMLRow::RenderMathMLRow(Element* element) - : RenderMathMLBlock(element) +RenderMathMLRow::RenderMathMLRow(Node* node) + : RenderMathMLBlock(node) { } -void RenderMathMLRow::layout() +// FIXME: Change all these createAnonymous... routines to return a PassOwnPtr<>. +RenderMathMLRow* RenderMathMLRow::createAnonymousWithParentRenderer(const RenderObject* parent) { - RenderBlock::layout(); - - LayoutUnit maxHeight = 0; + RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), INLINE_BLOCK); + RenderMathMLRow* newMRow = new (parent->renderArena()) RenderMathMLRow(parent->document() /* is anonymous */); + newMRow->setStyle(newStyle.release()); + return newMRow; +} - // Calculate the non-operator max height of the row. - for (RenderObject* current = firstChild(); current; current = current->nextSibling()) { - if (current->isRenderMathMLBlock()) { - RenderMathMLBlock* block = toRenderMathMLBlock(current); - if (!block->unembellishedOperator() && block->offsetHeight() > maxHeight) - maxHeight = block->offsetHeight(); - } else if (current->isBoxModelObject()) { - RenderBoxModelObject* box = toRenderBoxModelObject(current); - // Check to see if this box has a larger height. - if (box->offsetHeight() > maxHeight) - maxHeight = box->offsetHeight(); +void RenderMathMLRow::computePreferredLogicalWidths() +{ + ASSERT(preferredLogicalWidthsDirty() && needsLayout()); + + computeChildrenPreferredLogicalHeights(); + int stretchLogicalHeight = 0; + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + if (child->isRenderMathMLBlock()) { + RenderMathMLOperator* renderMo = toRenderMathMLBlock(child)->unembellishedOperator(); + // FIXME: Only skip renderMo if it is stretchy. + if (renderMo) + continue; } + stretchLogicalHeight = max<int>(stretchLogicalHeight, roundToInt(preferredLogicalHeightAfterSizing(child))); } + if (!stretchLogicalHeight) + stretchLogicalHeight = style()->fontSize(); - if (!maxHeight) - maxHeight = style()->fontSize(); - - // Stretch everything to the same height (blocks can ignore the request). - if (maxHeight > 0) { - bool didStretch = false; - for (RenderObject* current = firstChild(); current; current = current->nextSibling()) { - if (current->isRenderMathMLBlock()) { - RenderMathMLBlock* block = toRenderMathMLBlock(current); - block->stretchToHeight(maxHeight); - didStretch = true; - } - } - if (didStretch) { - setNeedsLayout(true); - setPreferredLogicalWidthsDirty(true, false); - RenderBlock::layout(); + // Set the sizes of (possibly embellished) stretchy operator children. + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + if (child->isRenderMathMLBlock()) { + RenderMathMLOperator* renderMo = toRenderMathMLBlock(child)->unembellishedOperator(); + if (renderMo) + renderMo->stretchToHeight(stretchLogicalHeight); } } -} + RenderMathMLBlock::computePreferredLogicalWidths(); + // Shrink our logical width to its probable value now without triggering unnecessary relayout of our children. + ASSERT(needsLayout() && logicalWidth() >= maxPreferredLogicalWidth()); + setLogicalWidth(maxPreferredLogicalWidth()); +} + +void RenderMathMLRow::layout() +{ + // Our computePreferredLogicalWidths() may change our logical width and then layout our children, which + // RenderBlock::layout()'s relayoutChildren logic isn't expecting. + if (preferredLogicalWidthsDirty()) + computePreferredLogicalWidths(); + + RenderMathMLBlock::layout(); +} + } #endif // ENABLE(MATHML) diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRow.h b/Source/WebCore/rendering/mathml/RenderMathMLRow.h index 2a520d07b..37f64a1db 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLRow.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLRow.h @@ -34,16 +34,21 @@ namespace WebCore { class RenderMathMLRow : public RenderMathMLBlock { public: - RenderMathMLRow(Element*); + RenderMathMLRow(Node*); + static RenderMathMLRow* createAnonymousWithParentRenderer(const RenderObject*); + virtual bool isRenderMathMLRow() const { return true; } - virtual void stretchToHeight(int) {} + protected: + // This also sets our stretchy embellished operator children to their correct sizes. + virtual void computePreferredLogicalWidths() OVERRIDE; + virtual void layout(); private: virtual const char* renderName() const { return isAnonymous() ? "RenderMathMLRow (anonymous)" : "RenderMathMLRow"; } }; - + } #endif // ENABLE(MATHML) diff --git a/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.cpp b/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.cpp index 206426a13..86975dbfb 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.cpp @@ -33,89 +33,119 @@ #include "GraphicsContext.h" #include "MathMLNames.h" #include "PaintInfo.h" -#include "Path.h" +#include "RenderMathMLRow.h" + +using namespace std; namespace WebCore { using namespace MathMLNames; -// Bottom padding of the radical (px) -const int gRadicalBasePad = 3; -// Threshold above which the radical shape is modified to look nice with big bases (%) -const float gThresholdBaseHeight = 1.5f; -// Radical width (%) -const float gRadicalWidth = 0.75f; -// Horizontal position of the bottom point of the radical (%) -const float gRadicalBottomPointXPos= 0.5f; -// Horizontal position of the top left point of the radical (%) -const float gRadicalTopLeftPointXPos = 0.2f; -// Vertical position of the top left point of the radical (%) -const float gRadicalTopLeftPointYPos = 0.5f; -// Vertical shift of the left end point of the radical (%) -const float gRadicalLeftEndYShift = 0.05f; -// Additional bottom root padding (%) -const float gRootBottomPadding = 0.2f; - -// Radical line thickness (%) -const float gRadicalLineThickness = 0.02f; -// Radical thick line thickness (%) -const float gRadicalThickLineThickness = 0.1f; +// FIXME: This whole file should be changed to work with various writing modes. See https://bugs.webkit.org/show_bug.cgi?id=48951. + +// Threshold above which the radical shape is modified to look nice with big bases (em) +const float gThresholdBaseHeightEms = 1.5f; +// Normal width of the front of the radical sign, before the base & overbar (em) +const float gFrontWidthEms = 0.75f; +// Gap between the base and overbar (em) +const float gSpaceAboveEms = 0.2f; +// Horizontal position of the bottom point of the radical (* frontWidth) +const float gRadicalBottomPointXFront = 0.5f; +// Lower the radical sign's bottom point (px) +const int gRadicalBottomPointLower = 3; +// Horizontal position of the top left point of the radical "dip" (* frontWidth) +const float gRadicalDipLeftPointXFront = 0.8f; +// Vertical position of the top left point of the radical "dip" (* baseHeight) +const float gRadicalDipLeftPointYPos = 0.5f; +// Vertical shift of the left end point of the radical (em) +const float gRadicalLeftEndYShiftEms = 0.05f; +// Additional bottom root padding if baseHeight > threshold (em) +const float gBigRootBottomPaddingEms = 0.2f; + +// Radical line thickness (em) +const float gRadicalLineThicknessEms = 0.02f; +// Radical thick line thickness (em) +const float gRadicalThickLineThicknessEms = 0.1f; RenderMathMLSquareRoot::RenderMathMLSquareRoot(Element* element) : RenderMathMLBlock(element) { } +void RenderMathMLSquareRoot::addChild(RenderObject* newChild, RenderObject* beforeChild) +{ + if (!firstChild()) { + RenderMathMLRow* newMRow = RenderMathMLRow::createAnonymousWithParentRenderer(this); + + RenderMathMLBlock::addChild(newMRow); + + // newMRow->isAnonymousBlock() is false because newMRow's display is INLINE_BLOCK, + // so we don't need to worry about removeLeftoverAnonymousBlock(). + ASSERT(!newMRow->isAnonymousBlock()); + } + + ASSERT(firstChild() && firstChild()->isAnonymous() && firstChild()->isRenderMathMLBlock() && toRenderMathMLBlock(firstChild())->isRenderMathMLRow()); + firstChild()->addChild(newChild, beforeChild); +} + +void RenderMathMLSquareRoot::computePreferredLogicalWidths() +{ + m_intrinsicPaddingStart = static_cast<int>(roundf(gFrontWidthEms * style()->fontSize())); + + RenderMathMLBlock::computePreferredLogicalWidths(); +} + +void RenderMathMLSquareRoot::computeLogicalHeight() +{ + int baseHeight = roundToInt(getBoxModelObjectHeight(firstChild())); + float thresholdHeight = gThresholdBaseHeightEms * style()->fontSize(); + m_intrinsicPaddingAfter = baseHeight > thresholdHeight ? static_cast<int>(roundf(gBigRootBottomPaddingEms * style()->fontSize())) : 0; + setLogicalHeight(baseHeight + borderAndPaddingLogicalHeight()); + + RenderMathMLBlock::computeLogicalHeight(); +} + +void RenderMathMLSquareRoot::layout() +{ + m_intrinsicPaddingBefore = static_cast<int>(roundf(gSpaceAboveEms * style()->fontSize())); + + RenderMathMLBlock::layout(); +} + void RenderMathMLSquareRoot::paint(PaintInfo& info, const LayoutPoint& paintOffset) { RenderMathMLBlock::paint(info, paintOffset); - + if (info.context->paintingDisabled()) return; + + IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + computedCSSContentBoxRect().location()); - IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location()); - - LayoutUnit maxHeight = 0; - LayoutUnit width = 0; - RenderObject* current = firstChild(); - while (current) { - if (current->isBoxModelObject()) { - - RenderBoxModelObject* box = toRenderBoxModelObject(current); - - // Check to see if this box has a larger height - if (box->offsetHeight() > maxHeight) - maxHeight = box->offsetHeight(); - width += box->offsetWidth(); - } - current = current->nextSibling(); - } - // default to the font size in pixels if we're empty - if (!maxHeight) - maxHeight = style()->fontSize(); + int baseHeight = roundToInt(getBoxModelObjectHeight(firstChild())); + int overbarWidth = roundToInt(getBoxModelObjectWidth(firstChild())); - int frontWidth = static_cast<int>(style()->fontSize() * gRadicalWidth); - int topStartShift = 0; + int frontWidth = m_intrinsicPaddingStart; + int overbarLeftPointShift = 0; // Base height above which the shape of the root changes - int thresholdHeight = static_cast<int>(gThresholdBaseHeight * style()->fontSize()); + float thresholdHeight = gThresholdBaseHeightEms * style()->fontSize(); - if (maxHeight > thresholdHeight && thresholdHeight) { - float shift = (maxHeight - thresholdHeight) / static_cast<float>(thresholdHeight); - if (shift > 1.) - shift = 1.0f; - topStartShift = static_cast<int>(gRadicalBottomPointXPos * frontWidth * shift); + if (baseHeight > thresholdHeight && thresholdHeight) { + float shift = min<float>((baseHeight - thresholdHeight) / thresholdHeight, 1.0f); + overbarLeftPointShift = static_cast<int>(shift * gRadicalBottomPointXFront * frontWidth); } - width += topStartShift; + overbarWidth += overbarLeftPointShift; - FloatPoint topStart(adjustedPaintOffset.x() + frontWidth - topStartShift, adjustedPaintOffset.y()); - FloatPoint bottomLeft(adjustedPaintOffset.x() + frontWidth * gRadicalBottomPointXPos , adjustedPaintOffset.y() + maxHeight + gRadicalBasePad); - FloatPoint topLeft(adjustedPaintOffset.x() + frontWidth * gRadicalTopLeftPointXPos , adjustedPaintOffset.y() + gRadicalTopLeftPointYPos * maxHeight); - FloatPoint leftEnd(adjustedPaintOffset.x() , topLeft.y() + gRadicalLeftEndYShift * style()->fontSize()); + int startX = adjustedPaintOffset.x() + frontWidth; + + FloatPoint overbarLeftPoint(startX - overbarLeftPointShift, adjustedPaintOffset.y()); + FloatPoint bottomPoint(startX - gRadicalBottomPointXFront * frontWidth, adjustedPaintOffset.y() + baseHeight + gRadicalBottomPointLower); + FloatPoint dipLeftPoint(startX - gRadicalDipLeftPointXFront * frontWidth, adjustedPaintOffset.y() + gRadicalDipLeftPointYPos * baseHeight); + FloatPoint leftEnd(startX - frontWidth, dipLeftPoint.y() + gRadicalLeftEndYShiftEms * style()->fontSize()); GraphicsContextStateSaver stateSaver(*info.context); - info.context->setStrokeThickness(gRadicalLineThickness * style()->fontSize()); + info.context->setStrokeThickness(gRadicalLineThicknessEms * style()->fontSize()); info.context->setStrokeStyle(SolidStroke); info.context->setStrokeColor(style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB); info.context->setLineJoin(MiterJoin); @@ -123,16 +153,16 @@ void RenderMathMLSquareRoot::paint(PaintInfo& info, const LayoutPoint& paintOffs Path root; - root.moveTo(FloatPoint(topStart.x() + width , adjustedPaintOffset.y())); + root.moveTo(FloatPoint(overbarLeftPoint.x() + overbarWidth, adjustedPaintOffset.y())); // draw top - root.addLineTo(topStart); + root.addLineTo(overbarLeftPoint); // draw from top left corner to bottom point of radical - root.addLineTo(bottomLeft); - // draw from bottom point to top of left part of radical base "pocket" - root.addLineTo(topLeft); + root.addLineTo(bottomPoint); + // draw from bottom point to top of left part of radical base "dip" + root.addLineTo(dipLeftPoint); // draw to end root.addLineTo(leftEnd); - + info.context->strokePath(root); GraphicsContextStateSaver maskStateSaver(*info.context); @@ -140,52 +170,24 @@ void RenderMathMLSquareRoot::paint(PaintInfo& info, const LayoutPoint& paintOffs // Build a mask to draw the thick part of the root. Path mask; - mask.moveTo(topStart); - mask.addLineTo(bottomLeft); - mask.addLineTo(topLeft); - mask.addLineTo(FloatPoint(2 * topLeft.x() - leftEnd.x(), 2 * topLeft.y() - leftEnd.y())); + mask.moveTo(overbarLeftPoint); + mask.addLineTo(bottomPoint); + mask.addLineTo(dipLeftPoint); + mask.addLineTo(FloatPoint(2 * dipLeftPoint.x() - leftEnd.x(), 2 * dipLeftPoint.y() - leftEnd.y())); info.context->clip(mask); // Draw the thick part of the root. - info.context->setStrokeThickness(gRadicalThickLineThickness * style()->fontSize()); + info.context->setStrokeThickness(gRadicalThickLineThicknessEms * style()->fontSize()); info.context->setLineCap(SquareCap); Path line; - line.moveTo(bottomLeft); - line.addLineTo(topLeft); + line.moveTo(bottomPoint); + line.addLineTo(dipLeftPoint); info.context->strokePath(line); } -void RenderMathMLSquareRoot::layout() -{ - LayoutUnit maxHeight = 0; - - RenderObject* current = firstChild(); - while (current) { - if (current->isBoxModelObject()) { - RenderBoxModelObject* box = toRenderBoxModelObject(current); - - if (box->offsetHeight() > maxHeight) - maxHeight = box->offsetHeight(); - - box->style()->setVerticalAlign(BASELINE); - } - current = current->nextSibling(); - } - - if (!maxHeight) - maxHeight = style()->fontSize(); - - - if (maxHeight > static_cast<LayoutUnit>(gThresholdBaseHeight * style()->fontSize())) - style()->setPaddingBottom(Length(static_cast<LayoutUnit>(gRootBottomPadding * style()->fontSize()), Fixed)); - - - RenderBlock::layout(); -} - } #endif // ENABLE(MATHML) diff --git a/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h b/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h index ad81fdc56..ea6d324db 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h @@ -32,15 +32,23 @@ namespace WebCore { +// Render sqrt(base), using radical notation. class RenderMathMLSquareRoot : public RenderMathMLBlock { public: RenderMathMLSquareRoot(Element*); - virtual void paint(PaintInfo&, const LayoutPoint&); -protected: - virtual void layout(); - + + virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE; + private: virtual const char* renderName() const { return "RenderMathMLSquareRoot"; } + + virtual bool createsAnonymousWrapper() const OVERRIDE { return true; } + + virtual void computePreferredLogicalWidths() OVERRIDE; + virtual void computeLogicalHeight() OVERRIDE; + virtual void layout() OVERRIDE; + + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; }; } diff --git a/Source/WebCore/rendering/mathml/RenderMathMLSubSup.cpp b/Source/WebCore/rendering/mathml/RenderMathMLSubSup.cpp index 84928d4b4..5342cbd84 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLSubSup.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLSubSup.cpp @@ -68,38 +68,31 @@ void RenderMathMLSubSup::addChild(RenderObject* child, RenderObject* beforeChild // Note: The RenderMathMLBlock only allows element children to be added. Element* childElement = toElement(child->node()); - if (!childElement->previousElementSibling()) { + if (childElement && !childElement->previousElementSibling()) { // Position 1 is always the base of the msub/msup/msubsup. - RenderMathMLBlock* wrapper = new (renderArena()) RenderMathMLBlock(node()); - RefPtr<RenderStyle> wrapperStyle = RenderStyle::create(); - wrapperStyle->inheritFrom(style()); - wrapperStyle->setDisplay(INLINE_BLOCK); - wrapperStyle->setVerticalAlign(BASELINE); - wrapper->setStyle(wrapperStyle.release()); - RenderMathMLBlock::addChild(wrapper, firstChild()); - wrapper->addChild(child); + RenderBlock* baseWrapper = createAlmostAnonymousBlock(INLINE_BLOCK); + RenderMathMLBlock::addChild(baseWrapper, firstChild()); + baseWrapper->addChild(child); // Make sure we have a script block for rendering. if (m_kind == SubSup && !m_scripts) { - m_scripts = new (renderArena()) RenderMathMLBlock(node()); - RefPtr<RenderStyle> scriptsStyle = RenderStyle::create(); - scriptsStyle->inheritFrom(style()); - scriptsStyle->setDisplay(INLINE_BLOCK); + RefPtr<RenderStyle> scriptsStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), INLINE_BLOCK); scriptsStyle->setVerticalAlign(TOP); scriptsStyle->setMarginLeft(Length(gSubsupScriptMargin, Fixed)); scriptsStyle->setTextAlign(LEFT); // Set this wrapper's font-size for its line-height & baseline position. scriptsStyle->setBlendedFontSize(static_cast<int>(0.75 * style()->fontSize())); - m_scripts->setStyle(scriptsStyle.release()); + m_scripts = new (renderArena()) RenderMathMLBlock(node()); + m_scripts->setStyle(scriptsStyle); RenderMathMLBlock::addChild(m_scripts, beforeChild); } } else { if (m_kind == SubSup) { - RenderBlock* script = new (renderArena()) RenderMathMLBlock(node()); - RefPtr<RenderStyle> scriptStyle = RenderStyle::create(); - scriptStyle->inheritFrom(m_scripts->style()); - scriptStyle->setDisplay(BLOCK); - script->setStyle(scriptStyle.release()); + ASSERT(childElement); + if (!childElement) + return; + + RenderBlock* script = m_scripts->createAlmostAnonymousBlock(); // The order is always backwards so the first script is the subscript and the superscript // is last. That means the superscript is the first to render vertically. @@ -123,13 +116,6 @@ RenderMathMLOperator* RenderMathMLSubSup::unembellishedOperator() return toRenderMathMLBlock(base)->unembellishedOperator(); } -void RenderMathMLSubSup::stretchToHeight(int height) -{ - RenderBoxModelObject* base = this->base(); - if (base && base->isRenderMathMLBlock()) - toRenderMathMLBlock(base)->stretchToHeight(height); -} - void RenderMathMLSubSup::layout() { RenderBlock::layout(); @@ -175,15 +161,15 @@ void RenderMathMLSubSup::layout() basePaddingTop = 0; } - setChildNeedsLayout(true, false); + setChildNeedsLayout(true, MarkOnlyThis); RenderObject* baseWrapper = firstChild(); baseWrapper->style()->setPaddingTop(Length(basePaddingTop, Fixed)); - baseWrapper->setNeedsLayout(true, false); + baseWrapper->setNeedsLayout(true, MarkOnlyThis); superscriptWrapper->style()->setPaddingBottom(Length(superPaddingBottom, Fixed)); - superscriptWrapper->setNeedsLayout(true, false); - m_scripts->setNeedsLayout(true, false); + superscriptWrapper->setNeedsLayout(true, MarkOnlyThis); + m_scripts->setNeedsLayout(true, MarkOnlyThis); RenderBlock::layout(); } diff --git a/Source/WebCore/rendering/mathml/RenderMathMLSubSup.h b/Source/WebCore/rendering/mathml/RenderMathMLSubSup.h index 0a291de97..c88fe663b 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLSubSup.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLSubSup.h @@ -32,13 +32,13 @@ namespace WebCore { +// Render a base with a subscript and/or a superscript. class RenderMathMLSubSup : public RenderMathMLBlock { public: RenderMathMLSubSup(Element*); virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); virtual RenderMathMLOperator* unembellishedOperator(); - virtual void stretchToHeight(int pixelHeight); protected: virtual void layout(); @@ -52,7 +52,7 @@ private: enum SubSupType { Sub, Sup, SubSup }; SubSupType m_kind; - RenderBlock* m_scripts; + RenderMathMLBlock* m_scripts; }; } diff --git a/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.cpp b/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.cpp index 0621cd6dd..03c9c31ef 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.cpp @@ -29,7 +29,6 @@ #include "RenderMathMLUnderOver.h" -#include "FontSelector.h" #include "MathMLNames.h" namespace WebCore { @@ -67,10 +66,7 @@ RenderBoxModelObject* RenderMathMLUnderOver::base() const void RenderMathMLUnderOver::addChild(RenderObject* child, RenderObject* beforeChild) { - RenderMathMLBlock* row = new (renderArena()) RenderMathMLBlock(node()); - RefPtr<RenderStyle> rowStyle = createBlockStyle(); - row->setStyle(rowStyle.release()); - row->setIsAnonymous(true); + RenderBlock* row = createAnonymousBlock(); // look through the children for rendered elements counting the blocks so we know what child // we are adding @@ -131,22 +127,12 @@ inline int getOffsetHeight(RenderObject* obj) { if (obj->isBoxModelObject()) { RenderBoxModelObject* box = toRenderBoxModelObject(obj); - return box->offsetHeight(); + return box->pixelSnappedOffsetHeight(); } return 0; } -void RenderMathMLUnderOver::stretchToHeight(int height) -{ - RenderBoxModelObject* base = this->base(); - if (base && base->isRenderMathMLBlock()) { - RenderMathMLBlock* block = toRenderMathMLBlock(base); - block->stretchToHeight(height); - setNeedsLayout(true); - } -} - void RenderMathMLUnderOver::layout() { RenderBlock::layout(); @@ -185,7 +171,7 @@ void RenderMathMLUnderOver::layout() // base row wrapper base = firstChild(); if (base) { - LayoutUnit baseHeight = getOffsetHeight(base); + int baseHeight = getOffsetHeight(base); // actual base base = base->firstChild(); if (!base || !base->isBoxModelObject()) @@ -226,7 +212,7 @@ void RenderMathMLUnderOver::layout() // We need to calculate the baseline of the base versus the start of the under block and // adjust the placement of the under block. - LayoutUnit baseHeight = getOffsetHeight(base); + int baseHeight = getOffsetHeight(base); // actual base base = base->firstChild(); if (!base || !base->isBoxModelObject()) diff --git a/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.h b/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.h index e25e94768..3a4f70d76 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLUnderOver.h @@ -40,7 +40,6 @@ public: virtual RenderMathMLOperator* unembellishedOperator(); virtual void layout(); virtual LayoutUnit baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; - virtual void stretchToHeight(int pixelHeight); private: virtual const char* renderName() const { return "RenderMathMLUnderOver"; } diff --git a/Source/WebCore/rendering/style/BorderValue.h b/Source/WebCore/rendering/style/BorderValue.h index d9d404b85..c8f6512c5 100644 --- a/Source/WebCore/rendering/style/BorderValue.h +++ b/Source/WebCore/rendering/style/BorderValue.h @@ -34,7 +34,9 @@ class BorderValue { friend class RenderStyle; public: BorderValue() - : m_width(3) + : m_color(0) + , m_colorIsValid(false) + , m_width(3) , m_style(BNONE) , m_isAuto(AUTO_OFF) { @@ -47,7 +49,7 @@ public: bool isTransparent() const { - return m_color.isValid() && !m_color.alpha(); + return m_colorIsValid && !alphaChannel(m_color); } bool isVisible(bool checkStyle = true) const @@ -57,21 +59,30 @@ public: bool operator==(const BorderValue& o) const { - return m_width == o.m_width && m_style == o.m_style && m_color == o.m_color; + return m_width == o.m_width && m_style == o.m_style && m_color == o.m_color && m_colorIsValid == o.m_colorIsValid; } bool operator!=(const BorderValue& o) const { return !(*this == o); } - - const Color& color() const { return m_color; } + + void setColor(const Color& color) + { + m_color = color.rgb(); + m_colorIsValid = color.isValid(); + } + + Color color() const { return Color(m_color, m_colorIsValid); } + unsigned width() const { return m_width; } EBorderStyle style() const { return static_cast<EBorderStyle>(m_style); } protected: - Color m_color; - unsigned m_width : 27; + RGBA32 m_color; + unsigned m_colorIsValid : 1; + + unsigned m_width : 26; unsigned m_style : 4; // EBorderStyle // This is only used by OutlineValue but moved here to keep the bits packed. diff --git a/Source/WebCore/rendering/style/CollapsedBorderValue.h b/Source/WebCore/rendering/style/CollapsedBorderValue.h index c84555e0c..049a4ac68 100644 --- a/Source/WebCore/rendering/style/CollapsedBorderValue.h +++ b/Source/WebCore/rendering/style/CollapsedBorderValue.h @@ -36,6 +36,15 @@ public: { } + // This copy constructor is for preventing GCC (x86) from creating an + // unexpected one as written in <http://webkit.org/b/81502>. + CollapsedBorderValue(const CollapsedBorderValue& other) + : m_border(other.m_border) + , m_borderColor(other.m_borderColor) + , m_precedence(other.m_precedence) + { + } + CollapsedBorderValue(const BorderValue& b, Color c, EBorderPrecedence p) : m_border(b) , m_borderColor(c) diff --git a/Source/WebCore/rendering/style/FillLayer.cpp b/Source/WebCore/rendering/style/FillLayer.cpp index c957cfe31..195a05c5d 100644 --- a/Source/WebCore/rendering/style/FillLayer.cpp +++ b/Source/WebCore/rendering/style/FillLayer.cpp @@ -24,11 +24,27 @@ namespace WebCore { +struct SameSizeAsFillLayer { + FillLayer* m_next; + + RefPtr<StyleImage> m_image; + + Length m_xPosition; + Length m_yPosition; + + LengthSize m_sizeLength; + + unsigned m_bitfields; +}; + +COMPILE_ASSERT(sizeof(FillLayer) == sizeof(SameSizeAsFillLayer), FillLayer_should_stay_small); + FillLayer::FillLayer(EFillLayerType type) : m_next(0) , m_image(FillLayer::initialFillImage(type)) , m_xPosition(FillLayer::initialFillXPosition(type)) , m_yPosition(FillLayer::initialFillYPosition(type)) + , m_sizeLength(FillLayer::initialFillSizeLength(type)) , m_attachment(FillLayer::initialFillAttachment(type)) , m_clip(FillLayer::initialFillClip(type)) , m_origin(FillLayer::initialFillOrigin(type)) @@ -36,7 +52,6 @@ FillLayer::FillLayer(EFillLayerType type) , m_repeatY(FillLayer::initialFillRepeatY(type)) , m_composite(FillLayer::initialFillComposite(type)) , m_sizeType(SizeNone) - , m_sizeLength(FillLayer::initialFillSizeLength(type)) , m_imageSet(false) , m_attachmentSet(false) , m_clipSet(false) @@ -55,6 +70,7 @@ FillLayer::FillLayer(const FillLayer& o) , m_image(o.m_image) , m_xPosition(o.m_xPosition) , m_yPosition(o.m_yPosition) + , m_sizeLength(o.m_sizeLength) , m_attachment(o.m_attachment) , m_clip(o.m_clip) , m_origin(o.m_origin) @@ -62,7 +78,6 @@ FillLayer::FillLayer(const FillLayer& o) , m_repeatY(o.m_repeatY) , m_composite(o.m_composite) , m_sizeType(o.m_sizeType) - , m_sizeLength(o.m_sizeLength) , m_imageSet(o.m_imageSet) , m_attachmentSet(o.m_attachmentSet) , m_clipSet(o.m_clipSet) @@ -91,6 +106,7 @@ FillLayer& FillLayer::operator=(const FillLayer& o) m_image = o.m_image; m_xPosition = o.m_xPosition; m_yPosition = o.m_yPosition; + m_sizeLength = o.m_sizeLength; m_attachment = o.m_attachment; m_clip = o.m_clip; m_composite = o.m_composite; @@ -98,7 +114,6 @@ FillLayer& FillLayer::operator=(const FillLayer& o) m_repeatX = o.m_repeatX; m_repeatY = o.m_repeatY; m_sizeType = o.m_sizeType; - m_sizeLength = o.m_sizeLength; m_imageSet = o.m_imageSet; m_attachmentSet = o.m_attachmentSet; diff --git a/Source/WebCore/rendering/style/FillLayer.h b/Source/WebCore/rendering/style/FillLayer.h index 2f0228874..7f1ceb148 100644 --- a/Source/WebCore/rendering/style/FillLayer.h +++ b/Source/WebCore/rendering/style/FillLayer.h @@ -174,6 +174,8 @@ private: Length m_xPosition; Length m_yPosition; + LengthSize m_sizeLength; + unsigned m_attachment : 2; // EFillAttachment unsigned m_clip : 2; // EFillBox unsigned m_origin : 2; // EFillBox @@ -182,17 +184,15 @@ private: unsigned m_composite : 4; // CompositeOperator unsigned m_sizeType : 2; // EFillSizeType - LengthSize m_sizeLength; - - bool m_imageSet : 1; - bool m_attachmentSet : 1; - bool m_clipSet : 1; - bool m_originSet : 1; - bool m_repeatXSet : 1; - bool m_repeatYSet : 1; - bool m_xPosSet : 1; - bool m_yPosSet : 1; - bool m_compositeSet : 1; + unsigned m_imageSet : 1; + unsigned m_attachmentSet : 1; + unsigned m_clipSet : 1; + unsigned m_originSet : 1; + unsigned m_repeatXSet : 1; + unsigned m_repeatYSet : 1; + unsigned m_xPosSet : 1; + unsigned m_yPosSet : 1; + unsigned m_compositeSet : 1; unsigned m_type : 1; // EFillLayerType }; diff --git a/Source/WebCore/rendering/style/KeyframeList.cpp b/Source/WebCore/rendering/style/KeyframeList.cpp index bafa4267c..a127b468b 100644 --- a/Source/WebCore/rendering/style/KeyframeList.cpp +++ b/Source/WebCore/rendering/style/KeyframeList.cpp @@ -85,11 +85,11 @@ void KeyframeList::insert(const KeyframeValue& keyframe) m_properties.clear(); for (Vector<KeyframeValue>::const_iterator it = m_keyframes.begin(); it != m_keyframes.end(); ++it) { const KeyframeValue& currKeyframe = *it; - for (HashSet<int>::const_iterator it = currKeyframe.properties().begin(); it != currKeyframe.properties().end(); ++it) + for (HashSet<CSSPropertyID>::const_iterator it = currKeyframe.properties().begin(); it != currKeyframe.properties().end(); ++it) m_properties.add(*it); } } else { - for (HashSet<int>::const_iterator it = keyframe.properties().begin(); it != keyframe.properties().end(); ++it) + for (HashSet<CSSPropertyID>::const_iterator it = keyframe.properties().begin(); it != keyframe.properties().end(); ++it) m_properties.add(*it); } } diff --git a/Source/WebCore/rendering/style/KeyframeList.h b/Source/WebCore/rendering/style/KeyframeList.h index 64170ce0c..fb352f9fd 100644 --- a/Source/WebCore/rendering/style/KeyframeList.h +++ b/Source/WebCore/rendering/style/KeyframeList.h @@ -25,6 +25,7 @@ #ifndef KeyframeList_h #define KeyframeList_h +#include "CSSPropertyNames.h" #include <wtf/Vector.h> #include <wtf/HashSet.h> #include <wtf/RefPtr.h> @@ -43,9 +44,9 @@ public: { } - void addProperty(int prop) { m_properties.add(prop); } - bool containsProperty(int prop) const { return m_properties.contains(prop); } - const HashSet<int>& properties() const { return m_properties; } + void addProperty(CSSPropertyID prop) { m_properties.add(prop); } + bool containsProperty(CSSPropertyID prop) const { return m_properties.contains(prop); } + const HashSet<CSSPropertyID>& properties() const { return m_properties; } float key() const { return m_key; } void setKey(float key) { m_key = key; } @@ -55,7 +56,7 @@ public: private: float m_key; - HashSet<int> m_properties; // The properties specified in this keyframe. + HashSet<CSSPropertyID> m_properties; // The properties specified in this keyframe. RefPtr<RenderStyle> m_style; }; @@ -77,10 +78,10 @@ public: void insert(const KeyframeValue& keyframe); - void addProperty(int prop) { m_properties.add(prop); } - bool containsProperty(int prop) const { return m_properties.contains(prop); } - HashSet<int>::const_iterator beginProperties() const { return m_properties.begin(); } - HashSet<int>::const_iterator endProperties() const { return m_properties.end(); } + void addProperty(CSSPropertyID prop) { m_properties.add(prop); } + bool containsProperty(CSSPropertyID prop) const { return m_properties.contains(prop); } + HashSet<CSSPropertyID>::const_iterator beginProperties() const { return m_properties.begin(); } + HashSet<CSSPropertyID>::const_iterator endProperties() const { return m_properties.end(); } void clear(); bool isEmpty() const { return m_keyframes.isEmpty(); } @@ -89,8 +90,8 @@ public: private: AtomicString m_animationName; - Vector<KeyframeValue> m_keyframes; // kept sorted by key - HashSet<int> m_properties; // the properties being animated + Vector<KeyframeValue> m_keyframes; // Kept sorted by key. + HashSet<CSSPropertyID> m_properties; // The properties being animated. RenderObject* m_renderer; }; diff --git a/Source/WebCore/rendering/style/OutlineValue.h b/Source/WebCore/rendering/style/OutlineValue.h index 0e9148d71..f380af628 100644 --- a/Source/WebCore/rendering/style/OutlineValue.h +++ b/Source/WebCore/rendering/style/OutlineValue.h @@ -39,7 +39,7 @@ public: bool operator==(const OutlineValue& o) const { - return m_width == o.m_width && m_style == o.m_style && m_color == o.m_color && m_offset == o.m_offset && m_isAuto == o.m_isAuto; + return m_width == o.m_width && m_style == o.m_style && m_color == o.m_color && m_colorIsValid == o.m_colorIsValid && m_offset == o.m_offset && m_isAuto == o.m_isAuto; } bool operator!=(const OutlineValue& o) const diff --git a/Source/WebCore/rendering/style/QuotesData.cpp b/Source/WebCore/rendering/style/QuotesData.cpp index 03a2554a2..4e81f7567 100644 --- a/Source/WebCore/rendering/style/QuotesData.cpp +++ b/Source/WebCore/rendering/style/QuotesData.cpp @@ -28,10 +28,10 @@ QuotesData* QuotesData::create(int stringCount) char* tmp = new char[sizeof(QuotesData)+sizeof(String)*stringCount]; if (!tmp) return 0; - new (tmp) QuotesData(stringCount); + QuotesData* ret = new (tmp) QuotesData(stringCount); for (int i = 0; i < stringCount; ++i) new (tmp +sizeof(QuotesData) + sizeof(String)*i) String(); - return reinterpret_cast<QuotesData*>(tmp); + return ret; } bool QuotesData::equal(const QuotesData* quotesData1, const QuotesData* quotesData2) diff --git a/Source/WebCore/rendering/style/RenderStyle.cpp b/Source/WebCore/rendering/style/RenderStyle.cpp index 8f31e0f7d..a98d558a1 100644 --- a/Source/WebCore/rendering/style/RenderStyle.cpp +++ b/Source/WebCore/rendering/style/RenderStyle.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2011 Adobe Systems Incorporated. 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 @@ -25,7 +26,6 @@ #include "ContentData.h" #include "CursorList.h" #include "CSSPropertyNames.h" -#include "CSSStyleSelector.h" #include "CSSWrapShapes.h" #include "FontSelector.h" #include "QuotesData.h" @@ -34,6 +34,7 @@ #include "ScaleTransformOperation.h" #include "ShadowData.h" #include "StyleImage.h" +#include "StyleResolver.h" #if ENABLE(TOUCH_EVENTS) #include "RenderTheme.h" #endif @@ -45,7 +46,7 @@ using namespace std; namespace WebCore { struct SameSizeAsBorderValue { - Color m_color; + RGBA32 m_color; unsigned m_width; }; @@ -86,11 +87,12 @@ PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle() return adoptRef(new RenderStyle(true)); } -PassRefPtr<RenderStyle> RenderStyle::createAnonymousStyle(const RenderStyle* parentStyle) +PassRefPtr<RenderStyle> RenderStyle::createAnonymousStyleWithDisplay(const RenderStyle* parentStyle, EDisplay display) { RefPtr<RenderStyle> newStyle = RenderStyle::create(); newStyle->inheritFrom(parentStyle); newStyle->inheritUnicodeBidiFrom(parentStyle); + newStyle->setDisplay(display); return newStyle; } @@ -221,7 +223,7 @@ bool RenderStyle::operator==(const RenderStyle& o) const bool RenderStyle::isStyleAvailable() const { - return this != CSSStyleSelector::styleNotYetAvailable(); + return this != StyleResolver::styleNotYetAvailable(); } static inline int pseudoBit(PseudoId pseudo) @@ -418,12 +420,6 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon #endif } -#if ENABLE(CSS_FILTERS) - if (rareNonInheritedData->m_filter.get() != other->rareNonInheritedData->m_filter.get() - && *rareNonInheritedData->m_filter.get() != *other->rareNonInheritedData->m_filter.get()) { - return StyleDifferenceLayout; - } -#endif #if ENABLE(CSS_GRID_LAYOUT) if (rareNonInheritedData->m_grid.get() != other->rareNonInheritedData->m_grid.get() && rareNonInheritedData->m_gridItem.get() != other->rareNonInheritedData->m_gridItem.get()) @@ -605,6 +601,18 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon #endif } +#if ENABLE(CSS_FILTERS) + if (rareNonInheritedData->m_filter.get() != other->rareNonInheritedData->m_filter.get() + && *rareNonInheritedData->m_filter.get() != *other->rareNonInheritedData->m_filter.get()) { +#if USE(ACCELERATED_COMPOSITING) + changedContextSensitiveProperties |= ContextSensitivePropertyFilter; + // Don't return; keep looking for another change. +#else + return StyleDifferenceRepaintLayer; +#endif + } +#endif + if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask || rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage) return StyleDifferenceRepaintLayer; @@ -769,39 +777,70 @@ void RenderStyle::setContent(QuoteType quote, bool add) rareNonInheritedData.access()->m_content = ContentData::create(quote); } - -void RenderStyle::applyTransform(TransformationMatrix& transform, const LayoutSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const + +inline bool requireTransformOrigin(const Vector<RefPtr<TransformOperation> >& transformOperations, RenderStyle::ApplyTransformOrigin applyOrigin) { // transform-origin brackets the transform with translate operations. // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant // in that case. - bool applyTransformOrigin = false; - unsigned s = rareNonInheritedData->m_transform->m_operations.operations().size(); - unsigned i; - if (applyOrigin == IncludeTransformOrigin) { - for (i = 0; i < s; i++) { - TransformOperation::OperationType type = rareNonInheritedData->m_transform->m_operations.operations()[i]->getOperationType(); - if (type != TransformOperation::TRANSLATE_X - && type != TransformOperation::TRANSLATE_Y - && type != TransformOperation::TRANSLATE - && type != TransformOperation::TRANSLATE_Z - && type != TransformOperation::TRANSLATE_3D - ) { - applyTransformOrigin = true; - break; - } - } - } + if (applyOrigin != RenderStyle::IncludeTransformOrigin) + return false; - if (applyTransformOrigin) { - transform.translate3d(transformOriginX().calcFloatValue(borderBoxSize.width()), transformOriginY().calcFloatValue(borderBoxSize.height()), transformOriginZ()); + unsigned size = transformOperations.size(); + for (unsigned i = 0; i < size; ++i) { + TransformOperation::OperationType type = transformOperations[i]->getOperationType(); + if (type != TransformOperation::TRANSLATE_X + && type != TransformOperation::TRANSLATE_Y + && type != TransformOperation::TRANSLATE + && type != TransformOperation::TRANSLATE_Z + && type != TransformOperation::TRANSLATE_3D) + return true; } + + return false; +} + +void RenderStyle::applyTransform(TransformationMatrix& transform, const LayoutSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const +{ + // FIXME: when subpixel layout is supported (bug 71143) the body of this function could be replaced by + // applyTransform(transform, FloatRect(FloatPoint(), borderBoxSize), applyOrigin); + + const Vector<RefPtr<TransformOperation> >& transformOperations = rareNonInheritedData->m_transform->m_operations.operations(); + bool applyTransformOrigin = requireTransformOrigin(transformOperations, applyOrigin); + + if (applyTransformOrigin) + transform.translate3d(floatValueForLength(transformOriginX(), borderBoxSize.width()), floatValueForLength(transformOriginY(), borderBoxSize.height()), transformOriginZ()); - for (i = 0; i < s; i++) - rareNonInheritedData->m_transform->m_operations.operations()[i]->apply(transform, borderBoxSize); + unsigned size = transformOperations.size(); + for (unsigned i = 0; i < size; ++i) + transformOperations[i]->apply(transform, borderBoxSize); + if (applyTransformOrigin) + transform.translate3d(-floatValueForLength(transformOriginX(), borderBoxSize.width()), -floatValueForLength(transformOriginY(), borderBoxSize.height()), -transformOriginZ()); +} + +void RenderStyle::applyTransform(TransformationMatrix& transform, const FloatRect& boundingBox, ApplyTransformOrigin applyOrigin) const +{ + const Vector<RefPtr<TransformOperation> >& transformOperations = rareNonInheritedData->m_transform->m_operations.operations(); + bool applyTransformOrigin = requireTransformOrigin(transformOperations, applyOrigin); + + float offsetX = transformOriginX().type() == Percent ? boundingBox.x() : 0; + float offsetY = transformOriginY().type() == Percent ? boundingBox.y() : 0; + + if (applyTransformOrigin) { + transform.translate3d(floatValueForLength(transformOriginX(), boundingBox.width()) + offsetX, + floatValueForLength(transformOriginY(), boundingBox.height()) + offsetY, + transformOriginZ()); + } + + unsigned size = transformOperations.size(); + for (unsigned i = 0; i < size; ++i) + transformOperations[i]->apply(transform, boundingBox.size()); + if (applyTransformOrigin) { - transform.translate3d(-transformOriginX().calcFloatValue(borderBoxSize.width()), -transformOriginY().calcFloatValue(borderBoxSize.height()), -transformOriginZ()); + transform.translate3d(-floatValueForLength(transformOriginX(), boundingBox.width()) - offsetX, + -floatValueForLength(transformOriginY(), boundingBox.height()) - offsetY, + -transformOriginZ()); } } @@ -842,17 +881,17 @@ void RenderStyle::setBoxShadow(PassOwnPtr<ShadowData> shadowData, bool add) rareData->m_boxShadow = shadowData; } -static RoundedRect::Radii calcRadiiFor(const BorderData& border, LayoutSize size) +static RoundedRect::Radii calcRadiiFor(const BorderData& border, IntSize size, RenderView* renderView) { return RoundedRect::Radii( - IntSize(border.topLeft().width().calcValue(size.width()), - border.topLeft().height().calcValue(size.height())), - IntSize(border.topRight().width().calcValue(size.width()), - border.topRight().height().calcValue(size.height())), - IntSize(border.bottomLeft().width().calcValue(size.width()), - border.bottomLeft().height().calcValue(size.height())), - IntSize(border.bottomRight().width().calcValue(size.width()), - border.bottomRight().height().calcValue(size.height()))); + IntSize(valueForLength(border.topLeft().width(), size.width(), renderView), + valueForLength(border.topLeft().height(), size.height(), renderView)), + IntSize(valueForLength(border.topRight().width(), size.width(), renderView), + valueForLength(border.topRight().height(), size.height(), renderView)), + IntSize(valueForLength(border.bottomLeft().width(), size.width(), renderView), + valueForLength(border.bottomLeft().height(), size.height(), renderView)), + IntSize(valueForLength(border.bottomRight().width(), size.width(), renderView), + valueForLength(border.bottomRight().height(), size.height(), renderView))); } static float calcConstraintScaleFor(const IntRect& rect, const RoundedRect::Radii& radii) @@ -887,12 +926,13 @@ static float calcConstraintScaleFor(const IntRect& rect, const RoundedRect::Radi return factor; } -RoundedRect RenderStyle::getRoundedBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const +RoundedRect RenderStyle::getRoundedBorderFor(const LayoutRect& borderRect, RenderView* renderView, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const { - RoundedRect roundedRect(pixelSnappedIntRect(borderRect)); + IntRect snappedBorderRect(pixelSnappedIntRect(borderRect)); + RoundedRect roundedRect(snappedBorderRect); if (hasBorderRadius()) { - RoundedRect::Radii radii = calcRadiiFor(surround->border, borderRect.size()); - radii.scale(calcConstraintScaleFor(borderRect, radii)); + RoundedRect::Radii radii = calcRadiiFor(surround->border, snappedBorderRect.size(), renderView); + radii.scale(calcConstraintScaleFor(snappedBorderRect, radii)); roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge); } return roundedRect; @@ -1095,12 +1135,12 @@ AnimationList* RenderStyle::accessTransitions() return rareNonInheritedData->m_transitions.get(); } -const Animation* RenderStyle::transitionForProperty(int property) const +const Animation* RenderStyle::transitionForProperty(CSSPropertyID property) const { if (transitions()) { for (size_t i = 0; i < transitions()->size(); ++i) { const Animation* p = transitions()->animation(i); - if (p->property() == cAnimateAll || p->property() == property) { + if (p->animationMode() == Animation::AnimateAll || p->property() == property) { return p; } } @@ -1130,10 +1170,10 @@ void RenderStyle::getShadowExtent(const ShadowData* shadow, LayoutUnit &top, Lay continue; int blurAndSpread = shadow->blur() + shadow->spread(); - top = min(top, shadow->y() - blurAndSpread); - right = max(right, shadow->x() + blurAndSpread); - bottom = max(bottom, shadow->y() + blurAndSpread); - left = min(left, shadow->x() - blurAndSpread); + top = min<LayoutUnit>(top, shadow->y() - blurAndSpread); + right = max<LayoutUnit>(right, shadow->x() + blurAndSpread); + bottom = max<LayoutUnit>(bottom, shadow->y() + blurAndSpread); + left = min<LayoutUnit>(left, shadow->x() - blurAndSpread); } } @@ -1147,8 +1187,8 @@ void RenderStyle::getShadowHorizontalExtent(const ShadowData* shadow, LayoutUnit continue; int blurAndSpread = shadow->blur() + shadow->spread(); - left = min(left, shadow->x() - blurAndSpread); - right = max(right, shadow->x() + blurAndSpread); + left = min<LayoutUnit>(left, shadow->x() - blurAndSpread); + right = max<LayoutUnit>(right, shadow->x() + blurAndSpread); } } @@ -1162,8 +1202,8 @@ void RenderStyle::getShadowVerticalExtent(const ShadowData* shadow, LayoutUnit & continue; int blurAndSpread = shadow->blur() + shadow->spread(); - top = min(top, shadow->y() - blurAndSpread); - bottom = max(bottom, shadow->y() + blurAndSpread); + top = min<LayoutUnit>(top, shadow->y() - blurAndSpread); + bottom = max<LayoutUnit>(bottom, shadow->y() + blurAndSpread); } } diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h index 55151d3ec..d57551497 100644 --- a/Source/WebCore/rendering/style/RenderStyle.h +++ b/Source/WebCore/rendering/style/RenderStyle.h @@ -39,6 +39,7 @@ #include "GraphicsTypes.h" #include "Length.h" #include "LengthBox.h" +#include "LengthFunctions.h" #include "LengthSize.h" #include "LineClampValue.h" #include "NinePieceImage.h" @@ -95,18 +96,22 @@ template<typename T, typename U> inline bool compareEqual(const T& t, const U& u if (!compareEqual(group->variable, value)) \ group.access()->variable = value; +#define SET_BORDERVALUE_COLOR(group, variable, value) \ + if (!compareEqual(group->variable.color(), value)) \ + group.access()->variable.setColor(value); + namespace WebCore { using std::max; class BorderData; -class CSSStyleSelector; class CounterContent; class CursorList; class IntRect; class Pair; class ShadowData; class StyleImage; +class StyleResolver; class TransformationMatrix; class ContentData; @@ -114,15 +119,15 @@ class ContentData; typedef Vector<RefPtr<RenderStyle>, 4> PseudoStyleCache; class RenderStyle: public RefCounted<RenderStyle> { - friend class AnimationBase; // Used by CSS animations. We can't allow them to animate based off visited colors. + friend class CSSPropertyAnimation; // Used by CSS animations. We can't allow them to animate based off visited colors. friend class ApplyStyleCommand; // Editing has to only reveal unvisited info. friend class EditingStyle; // Editing has to only reveal unvisited info. - friend class CSSStyleApplyProperty; // Sets members directly. - friend class CSSStyleSelector; // Sets members directly. friend class CSSComputedStyleDeclaration; // Ignores visited styles, so needs to be able to see unvisited info. friend class PropertyWrapperMaybeInvalidColor; // Used by CSS animations. We can't allow them to animate based off visited colors. friend class RenderSVGResource; // FIXME: Needs to alter the visited state by hand. Should clean the SVG code up and move it into RenderStyle perhaps. friend class RenderTreeAsText; // FIXME: Only needed so the render tree can keep lying and dump the wrong colors. Rebaselining would allow this to be yanked. + friend class StyleBuilder; // Sets members directly. + friend class StyleResolver; // Sets members directly. protected: class RenderStyleBitfields { @@ -214,7 +219,7 @@ protected: DataRef<SVGRenderStyle> m_svgStyle; #endif -// !START SYNC!: Keep this in sync with the copy constructor in RenderStyle.cpp and implicitlyInherited() in CSSStyleSelector.cpp +// !START SYNC!: Keep this in sync with the copy constructor in RenderStyle.cpp and implicitlyInherited() in StyleResolver.cpp // inherit struct InheritedFlags { @@ -385,7 +390,7 @@ private: public: static PassRefPtr<RenderStyle> create(); static PassRefPtr<RenderStyle> createDefaultStyle(); - static PassRefPtr<RenderStyle> createAnonymousStyle(const RenderStyle* parentStyle); + static PassRefPtr<RenderStyle> createAnonymousStyleWithDisplay(const RenderStyle* parentStyle, EDisplay); static PassRefPtr<RenderStyle> clone(const RenderStyle*); void inheritFrom(const RenderStyle* inheritParent); @@ -460,7 +465,7 @@ public: } #if ENABLE(CSS_FILTERS) - void getFilterOutsets(LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const + void getFilterOutsets(int& top, int& right, int& bottom, int& left) const { if (hasFilter()) filter().getOutsets(top, right, bottom, left); @@ -617,7 +622,7 @@ public: bool isLeftToRightDirection() const { return direction() == LTR; } Length lineHeight() const { return inherited->line_height; } - int computedLineHeight() const + int computedLineHeight(RenderView* renderView = 0) const { const Length& lh = inherited->line_height; @@ -626,7 +631,10 @@ public: return fontMetrics().lineSpacing(); if (lh.isPercent()) - return lh.calcMinValue(fontSize()); + return minimumValueForLength(lh, fontSize()); + + if (lh.isViewportPercentage()) + return valueForLength(lh, 0, renderView); return lh.value(); } @@ -799,10 +807,9 @@ public: EBoxOrient boxOrient() const { return static_cast<EBoxOrient>(rareNonInheritedData->m_deprecatedFlexibleBox->orient); } EBoxPack boxPack() const { return static_cast<EBoxPack>(rareNonInheritedData->m_deprecatedFlexibleBox->pack); } - float flexboxWidthPositiveFlex() const { return rareNonInheritedData->m_flexibleBox->m_widthPositiveFlex; } - float flexboxWidthNegativeFlex() const { return rareNonInheritedData->m_flexibleBox->m_widthNegativeFlex; } - float flexboxHeightPositiveFlex() const { return rareNonInheritedData->m_flexibleBox->m_heightPositiveFlex; } - float flexboxHeightNegativeFlex() const { return rareNonInheritedData->m_flexibleBox->m_heightNegativeFlex; } + float positiveFlex() const { return rareNonInheritedData->m_flexibleBox->m_positiveFlex; } + float negativeFlex() const { return rareNonInheritedData->m_flexibleBox->m_negativeFlex; } + Length flexPreferredSize() const { return rareNonInheritedData->m_flexibleBox->m_preferredSize; } int flexOrder() const { return rareNonInheritedData->m_flexibleBox->m_flexOrder; } EFlexPack flexPack() const { return static_cast<EFlexPack>(rareNonInheritedData->m_flexibleBox->m_flexPack); } EFlexAlign flexAlign() const { return static_cast<EFlexAlign>(rareNonInheritedData->m_flexibleBox->m_flexAlign); } @@ -811,6 +818,7 @@ public: bool isColumnFlexDirection() const { return flexDirection() == FlowColumn || flexDirection() == FlowColumnReverse; } bool isReverseFlexDirection() const { return flexDirection() == FlowRowReverse || flexDirection() == FlowColumnReverse; } EFlexWrap flexWrap() const { return static_cast<EFlexWrap>(rareNonInheritedData->m_flexibleBox->m_flexWrap); } + EFlexLinePack flexLinePack() const { return static_cast<EFlexLinePack>(rareNonInheritedData->m_flexibleBox->m_flexLinePack); } #if ENABLE(CSS_GRID_LAYOUT) const Vector<Length>& gridColumns() const { return rareNonInheritedData->m_grid->m_gridColumns; } @@ -894,6 +902,7 @@ public: enum ApplyTransformOrigin { IncludeTransformOrigin, ExcludeTransformOrigin }; void applyTransform(TransformationMatrix&, const LayoutSize& borderBoxSize, ApplyTransformOrigin = IncludeTransformOrigin) const; + void applyTransform(TransformationMatrix&, const FloatRect& boundingBox, ApplyTransformOrigin = IncludeTransformOrigin) const; void setPageScaleTransform(float); bool hasMask() const { return rareNonInheritedData->m_mask.hasImage() || rareNonInheritedData->m_maskBoxImage.hasImage(); } @@ -925,7 +934,7 @@ public: bool hasTransitions() const { return rareNonInheritedData->m_transitions && rareNonInheritedData->m_transitions->size() > 0; } // return the first found Animation (including 'all' transitions) - const Animation* transitionForProperty(int property) const; + const Animation* transitionForProperty(CSSPropertyID) const; ETransformStyle3D transformStyle3D() const { return static_cast<ETransformStyle3D>(rareNonInheritedData->m_transformStyle3D); } bool preserves3D() const { return rareNonInheritedData->m_transformStyle3D == TransformStyle3DPreserve3D; } @@ -1058,7 +1067,7 @@ public: setBorderRadius(LengthSize(Length(s.width(), Fixed), Length(s.height(), Fixed))); } - RoundedRect getRoundedBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; + RoundedRect getRoundedBorderFor(const LayoutRect& borderRect, RenderView* = 0, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; RoundedRect getRoundedInnerBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; RoundedRect getRoundedInnerBorderFor(const LayoutRect& borderRect, @@ -1066,21 +1075,21 @@ public: void setBorderLeftWidth(unsigned v) { SET_VAR(surround, border.m_left.m_width, v) } void setBorderLeftStyle(EBorderStyle v) { SET_VAR(surround, border.m_left.m_style, v) } - void setBorderLeftColor(const Color& v) { SET_VAR(surround, border.m_left.m_color, v) } + void setBorderLeftColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_left, v) } void setBorderRightWidth(unsigned v) { SET_VAR(surround, border.m_right.m_width, v) } void setBorderRightStyle(EBorderStyle v) { SET_VAR(surround, border.m_right.m_style, v) } - void setBorderRightColor(const Color& v) { SET_VAR(surround, border.m_right.m_color, v) } + void setBorderRightColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_right, v) } void setBorderTopWidth(unsigned v) { SET_VAR(surround, border.m_top.m_width, v) } void setBorderTopStyle(EBorderStyle v) { SET_VAR(surround, border.m_top.m_style, v) } - void setBorderTopColor(const Color& v) { SET_VAR(surround, border.m_top.m_color, v) } + void setBorderTopColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_top, v) } void setBorderBottomWidth(unsigned v) { SET_VAR(surround, border.m_bottom.m_width, v) } void setBorderBottomStyle(EBorderStyle v) { SET_VAR(surround, border.m_bottom.m_style, v) } - void setBorderBottomColor(const Color& v) { SET_VAR(surround, border.m_bottom.m_color, v) } + void setBorderBottomColor(const Color& v) { SET_BORDERVALUE_COLOR(surround, border.m_bottom, v) } void setOutlineWidth(unsigned short v) { SET_VAR(m_background, m_outline.m_width, v) } void setOutlineStyleIsAuto(OutlineIsAuto isAuto) { SET_VAR(m_background, m_outline.m_isAuto, isAuto) } void setOutlineStyle(EBorderStyle v) { SET_VAR(m_background, m_outline.m_style, v) } - void setOutlineColor(const Color& v) { SET_VAR(m_background, m_outline.m_color, v) } + void setOutlineColor(const Color& v) { SET_BORDERVALUE_COLOR(m_background, m_outline, v) } void setOverflowX(EOverflow v) { noninherited_flags._overflowX = v; } void setOverflowY(EOverflow v) { noninherited_flags._overflowY = v; } @@ -1223,7 +1232,7 @@ public: void setTextStrokeWidth(float w) { SET_VAR(rareInheritedData, textStrokeWidth, w) } void setTextFillColor(const Color& c) { SET_VAR(rareInheritedData, textFillColor, c) } void setColorSpace(ColorSpace space) { SET_VAR(rareInheritedData, colorSpace, space) } - void setOpacity(float f) { SET_VAR(rareNonInheritedData, opacity, f); } + void setOpacity(float f) { float v = clampTo<float>(f, 0, 1); SET_VAR(rareNonInheritedData, opacity, v); } void setAppearance(ControlPart a) { SET_VAR(rareNonInheritedData, m_appearance, a); } // For valid values of box-align see http://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#alignment void setBoxAlign(EBoxAlignment a) { SET_VAR(rareNonInheritedData.access()->m_deprecatedFlexibleBox, align, a); } @@ -1237,16 +1246,16 @@ public: void setBoxShadow(PassOwnPtr<ShadowData>, bool add = false); void setBoxReflect(PassRefPtr<StyleReflection> reflect) { if (rareNonInheritedData->m_boxReflect != reflect) rareNonInheritedData.access()->m_boxReflect = reflect; } void setBoxSizing(EBoxSizing s) { SET_VAR(m_box, m_boxSizing, s); } - void setFlexboxWidthPositiveFlex(float f) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_widthPositiveFlex, f); } - void setFlexboxWidthNegativeFlex(float f) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_widthNegativeFlex, f); } - void setFlexboxHeightPositiveFlex(float f) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_heightPositiveFlex, f); } - void setFlexboxHeightNegativeFlex(float f) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_heightNegativeFlex, f); } + void setPositiveFlex(float f) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_positiveFlex, f); } + void setNegativeFlex(float f) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_negativeFlex, f); } + void setFlexPreferredSize(Length l) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_preferredSize, l); } void setFlexOrder(int o) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexOrder, o); } void setFlexPack(EFlexPack p) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexPack, p); } void setFlexAlign(EFlexAlign a) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexAlign, a); } void setFlexItemAlign(EFlexAlign a) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexItemAlign, a); } void setFlexDirection(EFlexDirection direction) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexDirection, direction); } void setFlexWrap(EFlexWrap w) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexWrap, w); } + void setFlexLinePack(EFlexLinePack p) { SET_VAR(rareNonInheritedData.access()->m_flexibleBox, m_flexLinePack, p); } #if ENABLE(CSS_GRID_LAYOUT) void setGridColumns(const Vector<Length>& lengths) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridColumns, lengths); } void setGridRows(const Vector<Length>& lengths) { SET_VAR(rareNonInheritedData.access()->m_grid, m_gridRows, lengths); } @@ -1287,7 +1296,7 @@ public: void setHasAutoColumnCount() { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_autoCount, true); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_count, 0); } void setColumnGap(float f) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_normalGap, false); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_gap, f); } void setHasNormalColumnGap() { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_normalGap, true); SET_VAR(rareNonInheritedData.access()->m_multiCol, m_gap, 0); } - void setColumnRuleColor(const Color& c) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule.m_color, c); } + void setColumnRuleColor(const Color& c) { SET_BORDERVALUE_COLOR(rareNonInheritedData.access()->m_multiCol, m_rule, c); } void setColumnRuleStyle(EBorderStyle b) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule.m_style, b); } void setColumnRuleWidth(unsigned short w) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule.m_width, w); } void resetColumnRule() { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_rule, BorderValue()) } @@ -1376,13 +1385,13 @@ public: SVGRenderStyle* accessSVGStyle() { return m_svgStyle.access(); } const SVGPaint::SVGPaintType& fillPaintType() const { return svgStyle()->fillPaintType(); } - const Color& fillPaintColor() const { return svgStyle()->fillPaintColor(); } + Color fillPaintColor() const { return svgStyle()->fillPaintColor(); } void setFillPaintColor(const Color& c) { accessSVGStyle()->setFillPaint(SVGPaint::SVG_PAINTTYPE_RGBCOLOR, c, ""); } float fillOpacity() const { return svgStyle()->fillOpacity(); } void setFillOpacity(float f) { accessSVGStyle()->setFillOpacity(f); } const SVGPaint::SVGPaintType& strokePaintType() const { return svgStyle()->strokePaintType(); } - const Color& strokePaintColor() const { return svgStyle()->strokePaintColor(); } + Color strokePaintColor() const { return svgStyle()->strokePaintColor(); } void setStrokePaintColor(const Color& c) { accessSVGStyle()->setStrokePaint(SVGPaint::SVG_PAINTTYPE_RGBCOLOR, c, ""); } float strokeOpacity() const { return svgStyle()->strokeOpacity(); } void setStrokeOpacity(float f) { accessSVGStyle()->setStrokeOpacity(f); } @@ -1456,9 +1465,21 @@ public: StyleDifference diff(const RenderStyle*, unsigned& changedContextSensitiveProperties) const; - bool isDisplayReplacedType() const { return isDisplayReplacedType(display()); } - bool isDisplayInlineType() const { return isDisplayInlineType(display()); } - bool isOriginalDisplayInlineType() const { return isDisplayInlineType(originalDisplay()); } + bool isDisplayReplacedType() const + { + return display() == INLINE_BLOCK || display() == INLINE_BOX || display() == INLINE_TABLE; + } + + bool isDisplayInlineType() const + { + return display() == INLINE || isDisplayReplacedType(); + } + + bool isOriginalDisplayInlineType() const + { + return originalDisplay() == INLINE || originalDisplay() == INLINE_BLOCK + || originalDisplay() == INLINE_BOX || originalDisplay() == INLINE_TABLE; + } void setWritingMode(WritingMode v) { inherited_flags.m_writingMode = v; } @@ -1559,16 +1580,16 @@ public: static unsigned int initialBoxOrdinalGroup() { return 1; } static EBoxSizing initialBoxSizing() { return CONTENT_BOX; } static StyleReflection* initialBoxReflect() { return 0; } - static float initialFlexboxWidthPositiveFlex() { return 0; } - static float initialFlexboxWidthNegativeFlex() { return 0; } - static float initialFlexboxHeightPositiveFlex() { return 0; } - static float initialFlexboxHeightNegativeFlex() { return 0; } + static float initialPositiveFlex() { return 0; } + static float initialNegativeFlex() { return 0; } + static Length initialFlexPreferredSize() { return Length(Auto); } static int initialFlexOrder() { return 0; } static EFlexPack initialFlexPack() { return PackStart; } static EFlexAlign initialFlexAlign() { return AlignStretch; } static EFlexAlign initialFlexItemAlign() { return AlignAuto; } static EFlexDirection initialFlexDirection() { return FlowRow; } static EFlexWrap initialFlexWrap() { return FlexWrapNone; } + static EFlexLinePack initialFlexLinePack() { return LinePackStretch; } static int initialMarqueeLoopCount() { return -1; } static int initialMarqueeSpeed() { return 85; } static Length initialMarqueeIncrement() { return Length(6, Fixed); } @@ -1709,43 +1730,37 @@ private: return isHorizontalWritingMode() ? getImageVerticalOutsets(image, logicalTop, logicalBottom) : getImageHorizontalOutsets(image, logicalTop, logicalBottom); } - bool isDisplayReplacedType(EDisplay display) const - { - return display == INLINE_BLOCK || display == INLINE_BOX || display == INLINE_FLEXBOX || display == INLINE_TABLE; - } - bool isDisplayInlineType(EDisplay display) const { return display == INLINE || isDisplayReplacedType(display); } - // Color accessors are all private to make sure callers use visitedDependentColor instead to access them. - const Color& invalidColor() const { static Color invalid; return invalid; } - const Color& borderLeftColor() const { return surround->border.left().color(); } - const Color& borderRightColor() const { return surround->border.right().color(); } - const Color& borderTopColor() const { return surround->border.top().color(); } - const Color& borderBottomColor() const { return surround->border.bottom().color(); } - const Color& backgroundColor() const { return m_background->color(); } - const Color& color() const { return inherited->color; } - const Color& columnRuleColor() const { return rareNonInheritedData->m_multiCol->m_rule.color(); } - const Color& outlineColor() const { return m_background->outline().color(); } - const Color& textEmphasisColor() const { return rareInheritedData->textEmphasisColor; } - const Color& textFillColor() const { return rareInheritedData->textFillColor; } - const Color& textStrokeColor() const { return rareInheritedData->textStrokeColor; } - const Color& visitedLinkColor() const { return inherited->visitedLinkColor; } - const Color& visitedLinkBackgroundColor() const { return rareNonInheritedData->m_visitedLinkBackgroundColor; } - const Color& visitedLinkBorderLeftColor() const { return rareNonInheritedData->m_visitedLinkBorderLeftColor; } - const Color& visitedLinkBorderRightColor() const { return rareNonInheritedData->m_visitedLinkBorderRightColor; } - const Color& visitedLinkBorderBottomColor() const { return rareNonInheritedData->m_visitedLinkBorderBottomColor; } - const Color& visitedLinkBorderTopColor() const { return rareNonInheritedData->m_visitedLinkBorderTopColor; } - const Color& visitedLinkOutlineColor() const { return rareNonInheritedData->m_visitedLinkOutlineColor; } - const Color& visitedLinkColumnRuleColor() const { return rareNonInheritedData->m_multiCol->m_visitedLinkColumnRuleColor; } - const Color& visitedLinkTextEmphasisColor() const { return rareInheritedData->visitedLinkTextEmphasisColor; } - const Color& visitedLinkTextFillColor() const { return rareInheritedData->visitedLinkTextFillColor; } - const Color& visitedLinkTextStrokeColor() const { return rareInheritedData->visitedLinkTextStrokeColor; } + Color invalidColor() const { static Color invalid; return invalid; } + Color borderLeftColor() const { return surround->border.left().color(); } + Color borderRightColor() const { return surround->border.right().color(); } + Color borderTopColor() const { return surround->border.top().color(); } + Color borderBottomColor() const { return surround->border.bottom().color(); } + Color backgroundColor() const { return m_background->color(); } + Color color() const { return inherited->color; } + Color columnRuleColor() const { return rareNonInheritedData->m_multiCol->m_rule.color(); } + Color outlineColor() const { return m_background->outline().color(); } + Color textEmphasisColor() const { return rareInheritedData->textEmphasisColor; } + Color textFillColor() const { return rareInheritedData->textFillColor; } + Color textStrokeColor() const { return rareInheritedData->textStrokeColor; } + Color visitedLinkColor() const { return inherited->visitedLinkColor; } + Color visitedLinkBackgroundColor() const { return rareNonInheritedData->m_visitedLinkBackgroundColor; } + Color visitedLinkBorderLeftColor() const { return rareNonInheritedData->m_visitedLinkBorderLeftColor; } + Color visitedLinkBorderRightColor() const { return rareNonInheritedData->m_visitedLinkBorderRightColor; } + Color visitedLinkBorderBottomColor() const { return rareNonInheritedData->m_visitedLinkBorderBottomColor; } + Color visitedLinkBorderTopColor() const { return rareNonInheritedData->m_visitedLinkBorderTopColor; } + Color visitedLinkOutlineColor() const { return rareNonInheritedData->m_visitedLinkOutlineColor; } + Color visitedLinkColumnRuleColor() const { return rareNonInheritedData->m_multiCol->m_visitedLinkColumnRuleColor; } + Color visitedLinkTextEmphasisColor() const { return rareInheritedData->visitedLinkTextEmphasisColor; } + Color visitedLinkTextFillColor() const { return rareInheritedData->visitedLinkTextFillColor; } + Color visitedLinkTextStrokeColor() const { return rareInheritedData->visitedLinkTextStrokeColor; } Color colorIncludingFallback(int colorProperty, bool visitedLink) const; #if ENABLE(SVG) - const Color& stopColor() const { return svgStyle()->stopColor(); } - const Color& floodColor() const { return svgStyle()->floodColor(); } - const Color& lightingColor() const { return svgStyle()->lightingColor(); } + Color stopColor() const { return svgStyle()->stopColor(); } + Color floodColor() const { return svgStyle()->floodColor(); } + Color lightingColor() const { return svgStyle()->lightingColor(); } #endif void appendContent(PassOwnPtr<ContentData>); @@ -1764,7 +1779,7 @@ inline int adjustForAbsoluteZoom(int value, const RenderStyle* style) value++; } - return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(value / zoomFactor); + return roundForImpreciseConversion<int>(value / zoomFactor); } inline float adjustFloatForAbsoluteZoom(float value, const RenderStyle* style) diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h index aee10813a..741acc6e5 100644 --- a/Source/WebCore/rendering/style/RenderStyleConstants.h +++ b/Source/WebCore/rendering/style/RenderStyleConstants.h @@ -63,7 +63,8 @@ enum StyleDifference { enum StyleDifferenceContextSensitiveProperty { ContextSensitivePropertyNone = 0, ContextSensitivePropertyTransform = (1 << 0), - ContextSensitivePropertyOpacity = (1 << 1) + ContextSensitivePropertyOpacity = (1 << 1), + ContextSensitivePropertyFilter = (1 << 2) }; // Static pseudo styles. Dynamic ones are produced on the fly. @@ -97,7 +98,7 @@ enum EPosition { }; enum EFloat { - NoFloat, LeftFloat, RightFloat, PositionedFloat + NoFloat, LeftFloat, RightFloat }; enum EMarginCollapse { MCOLLAPSE, MSEPARATE, MDISCARD }; @@ -171,6 +172,7 @@ enum EBoxDirection { BNORMAL, BREVERSE }; enum EFlexPack { PackStart, PackEnd, PackCenter, PackJustify, PackDistribute }; enum EFlexAlign { AlignAuto, AlignStart, AlignEnd, AlignCenter, AlignStretch, AlignBaseline }; enum EFlexDirection { FlowRow, FlowRowReverse, FlowColumn, FlowColumnReverse }; +enum EFlexLinePack { LinePackStart, LinePackEnd, LinePackCenter, LinePackJustify, LinePackDistribute, LinePackStretch }; enum EFlexWrap { FlexWrapNone, FlexWrap, FlexWrapReverse }; enum ETextSecurity { @@ -458,7 +460,7 @@ enum LineSnap { LineSnapNone, LineSnapBaseline, LineSnapContain }; enum LineAlign { LineAlignNone, LineAlignEdges }; -enum WrapFlow { WrapFlowAuto, WrapFlowBoth, WrapFlowLeft, WrapFlowRight, WrapFlowMaximum, WrapFlowClear }; +enum WrapFlow { WrapFlowAuto, WrapFlowBoth, WrapFlowStart, WrapFlowEnd, WrapFlowMaximum, WrapFlowClear }; enum WrapThrough { WrapThroughWrap, WrapThroughNone }; diff --git a/Source/WebCore/rendering/style/SVGRenderStyle.h b/Source/WebCore/rendering/style/SVGRenderStyle.h index 6539f719a..e8984c048 100644 --- a/Source/WebCore/rendering/style/SVGRenderStyle.h +++ b/Source/WebCore/rendering/style/SVGRenderStyle.h @@ -362,6 +362,7 @@ public: bool hasFilter() const { return !filterResource().isEmpty(); } bool hasMarkers() const { return !markerStartResource().isEmpty() || !markerMidResource().isEmpty() || !markerEndResource().isEmpty(); } bool hasStroke() const { return strokePaintType() != SVGPaint::SVG_PAINTTYPE_NONE; } + bool hasVisibleStroke() const { return hasStroke() && !strokeWidth().isZero(); } bool hasFill() const { return fillPaintType() != SVGPaint::SVG_PAINTTYPE_NONE; } bool isVerticalWritingMode() const { return writingMode() == WM_TBRL || writingMode() == WM_TB; } diff --git a/Source/WebCore/rendering/style/ShadowData.cpp b/Source/WebCore/rendering/style/ShadowData.cpp index c359cbf62..f30d87f2b 100644 --- a/Source/WebCore/rendering/style/ShadowData.cpp +++ b/Source/WebCore/rendering/style/ShadowData.cpp @@ -27,8 +27,7 @@ using namespace std; namespace WebCore { ShadowData::ShadowData(const ShadowData& o) - : m_x(o.m_x) - , m_y(o.m_y) + : m_location(o.m_location) , m_blur(o.m_blur) , m_spread(o.m_spread) , m_color(o.m_color) @@ -44,8 +43,7 @@ bool ShadowData::operator==(const ShadowData& o) const || (m_next && o.m_next && *m_next != *o.m_next)) return false; - return m_x == o.m_x - && m_y == o.m_y + return m_location == o.m_location && m_blur == o.m_blur && m_spread == o.m_spread && m_style == o.m_style @@ -53,7 +51,7 @@ bool ShadowData::operator==(const ShadowData& o) const && m_isWebkitBoxShadow == o.m_isWebkitBoxShadow; } -static inline void calculateShadowExtent(const ShadowData* shadow, int additionalOutlineSize, LayoutUnit& shadowLeft, LayoutUnit& shadowRight, LayoutUnit& shadowTop, LayoutUnit& shadowBottom) +static inline void calculateShadowExtent(const ShadowData* shadow, int additionalOutlineSize, int& shadowLeft, int& shadowRight, int& shadowTop, int& shadowBottom) { do { int blurAndSpread = shadow->blur() + shadow->spread() + additionalOutlineSize; @@ -68,12 +66,12 @@ static inline void calculateShadowExtent(const ShadowData* shadow, int additiona } while (shadow); } -void ShadowData::adjustRectForShadow(IntRect& rect, int additionalOutlineSize) const +void ShadowData::adjustRectForShadow(LayoutRect& rect, int additionalOutlineSize) const { - LayoutUnit shadowLeft = 0; - LayoutUnit shadowRight = 0; - LayoutUnit shadowTop = 0; - LayoutUnit shadowBottom = 0; + int shadowLeft = 0; + int shadowRight = 0; + int shadowTop = 0; + int shadowBottom = 0; calculateShadowExtent(this, additionalOutlineSize, shadowLeft, shadowRight, shadowTop, shadowBottom); rect.move(shadowLeft, shadowTop); @@ -83,10 +81,10 @@ void ShadowData::adjustRectForShadow(IntRect& rect, int additionalOutlineSize) c void ShadowData::adjustRectForShadow(FloatRect& rect, int additionalOutlineSize) const { - LayoutUnit shadowLeft = 0; - LayoutUnit shadowRight = 0; - LayoutUnit shadowTop = 0; - LayoutUnit shadowBottom = 0; + int shadowLeft = 0; + int shadowRight = 0; + int shadowTop = 0; + int shadowBottom = 0; calculateShadowExtent(this, additionalOutlineSize, shadowLeft, shadowRight, shadowTop, shadowBottom); rect.move(shadowLeft, shadowTop); diff --git a/Source/WebCore/rendering/style/ShadowData.h b/Source/WebCore/rendering/style/ShadowData.h index fea8d3d02..b8df95d88 100644 --- a/Source/WebCore/rendering/style/ShadowData.h +++ b/Source/WebCore/rendering/style/ShadowData.h @@ -40,18 +40,15 @@ class ShadowData { WTF_MAKE_FAST_ALLOCATED; public: ShadowData() - : m_x(0) - , m_y(0) - , m_blur(0) + : m_blur(0) , m_spread(0) , m_style(Normal) , m_isWebkitBoxShadow(false) { } - ShadowData(LayoutUnit x, LayoutUnit y, int blur, int spread, ShadowStyle style, bool isWebkitBoxShadow, const Color& color) - : m_x(x) - , m_y(y) + ShadowData(const IntPoint& location, int blur, int spread, ShadowStyle style, bool isWebkitBoxShadow, const Color& color) + : m_location(location) , m_blur(blur) , m_spread(spread) , m_color(color) @@ -68,8 +65,9 @@ public: return !(*this == o); } - LayoutUnit x() const { return m_x; } - LayoutUnit y() const { return m_y; } + int x() const { return m_location.x(); } + int y() const { return m_location.y(); } + IntPoint location() const { return m_location; } int blur() const { return m_blur; } int spread() const { return m_spread; } ShadowStyle style() const { return m_style; } @@ -79,12 +77,11 @@ public: const ShadowData* next() const { return m_next.get(); } void setNext(PassOwnPtr<ShadowData> shadow) { m_next = shadow; } - void adjustRectForShadow(IntRect&, int additionalOutlineSize = 0) const; + void adjustRectForShadow(LayoutRect&, int additionalOutlineSize = 0) const; void adjustRectForShadow(FloatRect&, int additionalOutlineSize = 0) const; private: - LayoutUnit m_x; - LayoutUnit m_y; + IntPoint m_location; int m_blur; int m_spread; Color m_color; diff --git a/Source/WebCore/rendering/style/StyleCachedImageSet.cpp b/Source/WebCore/rendering/style/StyleCachedImageSet.cpp new file mode 100644 index 000000000..f5071d169 --- /dev/null +++ b/Source/WebCore/rendering/style/StyleCachedImageSet.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "StyleCachedImageSet.h" + +#if ENABLE(CSS_IMAGE_SET) + +#include "CSSImageSetValue.h" +#include "CachedImage.h" +#include "RenderObject.h" + +namespace WebCore { + +StyleCachedImageSet::StyleCachedImageSet(CachedImage* image, float imageScaleFactor, CSSImageSetValue* value) + : m_bestFitImage(image) + , m_imageScaleFactor(imageScaleFactor) + , m_imageSetValue(value) +{ + m_isCachedImageSet = true; + m_bestFitImage->addClient(this); +} + + +StyleCachedImageSet::~StyleCachedImageSet() +{ + m_bestFitImage->removeClient(this); +} + +PassRefPtr<CSSValue> StyleCachedImageSet::cssValue() const +{ + return m_imageSetValue; +} + +bool StyleCachedImageSet::canRender(const RenderObject* renderer, float multiplier) const +{ + return m_bestFitImage->canRender(renderer, multiplier); +} + +bool StyleCachedImageSet::isLoaded() const +{ + return m_bestFitImage->isLoaded(); +} + +bool StyleCachedImageSet::errorOccurred() const +{ + return m_bestFitImage->errorOccurred(); +} + +IntSize StyleCachedImageSet::imageSize(const RenderObject* renderer, float multiplier) const +{ + IntSize scaledImageSize = m_bestFitImage->imageSizeForRenderer(renderer, multiplier); + scaledImageSize.scale(1 / m_imageScaleFactor); + return scaledImageSize; +} + +bool StyleCachedImageSet::imageHasRelativeWidth() const +{ + return m_bestFitImage->imageHasRelativeWidth(); +} + +bool StyleCachedImageSet::imageHasRelativeHeight() const +{ + return m_bestFitImage->imageHasRelativeHeight(); +} + +void StyleCachedImageSet::computeIntrinsicDimensions(const RenderObject*, Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio) +{ + m_bestFitImage->computeIntrinsicDimensions(intrinsicWidth, intrinsicHeight, intrinsicRatio); +} + +bool StyleCachedImageSet::usesImageContainerSize() const +{ + return m_bestFitImage->usesImageContainerSize(); +} + +void StyleCachedImageSet::setContainerSizeForRenderer(const RenderObject* renderer, const IntSize& imageContainerSize, float imageContainerZoomFactor) +{ + m_bestFitImage->setContainerSizeForRenderer(renderer, imageContainerSize, imageContainerZoomFactor); +} + +void StyleCachedImageSet::addClient(RenderObject* renderer) +{ + m_bestFitImage->addClient(renderer); +} + +void StyleCachedImageSet::removeClient(RenderObject* renderer) +{ + m_bestFitImage->removeClientForRenderer(renderer); +} + +PassRefPtr<Image> StyleCachedImageSet::image(RenderObject* renderer, const IntSize&) const +{ + return m_bestFitImage->imageForRenderer(renderer); +} + +} // namespace WebCore + +#endif // ENABLE(CSS_IMAGE_SET) diff --git a/Source/WebCore/rendering/style/StyleCachedImageSet.h b/Source/WebCore/rendering/style/StyleCachedImageSet.h new file mode 100644 index 000000000..d35947fb3 --- /dev/null +++ b/Source/WebCore/rendering/style/StyleCachedImageSet.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef StyleCachedImageSet_h +#define StyleCachedImageSet_h + +#if ENABLE(CSS_IMAGE_SET) + +#include "CachedImage.h" +#include "CachedResourceHandle.h" +#include "StyleImage.h" + +namespace WebCore { + +class CachedImage; +class CSSImageSetValue; + +// This class keeps one cached image and has access to a set of alternatives. + +class StyleCachedImageSet : public StyleImage, private CachedImageClient { + WTF_MAKE_FAST_ALLOCATED; +public: + static PassRefPtr<StyleCachedImageSet> create(CachedImage* image, float imageScaleFactor, CSSImageSetValue* value) + { + return adoptRef(new StyleCachedImageSet(image, imageScaleFactor, value)); + } + virtual ~StyleCachedImageSet(); + + virtual PassRefPtr<CSSValue> cssValue() const; + + // FIXME: This is used by StyleImage for equals comparison, but this implementation + // only looks at the image from the set that we have loaded. I'm not sure if that is + // meaningful enough or not. + virtual WrappedImagePtr data() const { return m_bestFitImage.get(); } + + CachedImage* cachedImage() const { return m_bestFitImage.get(); } + + virtual bool canRender(const RenderObject*, float multiplier) const; + virtual bool isLoaded() const; + virtual bool errorOccurred() const; + virtual IntSize imageSize(const RenderObject*, float multiplier) const; + virtual bool imageHasRelativeWidth() const; + virtual bool imageHasRelativeHeight() const; + virtual void computeIntrinsicDimensions(const RenderObject*, Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio); + virtual bool usesImageContainerSize() const; + virtual void setContainerSizeForRenderer(const RenderObject*, const IntSize&, float); + virtual void addClient(RenderObject*); + virtual void removeClient(RenderObject*); + virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const; + virtual float imageScaleFactor() const { return m_imageScaleFactor; } + +private: + StyleCachedImageSet(CachedImage*, float imageScaleFactor, CSSImageSetValue*); + + CachedResourceHandle<CachedImage> m_bestFitImage; + float m_imageScaleFactor; + CSSImageSetValue* m_imageSetValue; // Not retained; it owns us. +}; + +} // namespace WebCore + +#endif // ENABLE(CSS_IMAGE_SET) + +#endif // StyleCachedImageSet_h diff --git a/Source/WebCore/rendering/style/StyleCustomFilterProgram.h b/Source/WebCore/rendering/style/StyleCustomFilterProgram.h index b6eec7470..bff09a98c 100644 --- a/Source/WebCore/rendering/style/StyleCustomFilterProgram.h +++ b/Source/WebCore/rendering/style/StyleCustomFilterProgram.h @@ -113,6 +113,16 @@ public: if (isLoaded()) notifyClients(); } + + CachedShader* cachedVertexShader() const { return m_vertexShader ? m_vertexShader->cachedShader() : 0; } + CachedShader* cachedFragmentShader() const { return m_fragmentShader ? m_fragmentShader->cachedShader() : 0; } + + virtual bool operator==(const CustomFilterProgram& o) const + { + // The following cast is ugly, but StyleCustomFilterProgram is the single implementation of CustomFilterProgram. + const StyleCustomFilterProgram* other = static_cast<const StyleCustomFilterProgram*>(&o); + return cachedVertexShader() == other->cachedVertexShader() && cachedFragmentShader() == other->cachedFragmentShader(); + } private: StyleCustomFilterProgram(PassRefPtr<StyleShader> vertexShader, PassRefPtr<StyleShader> fragmentShader) diff --git a/Source/WebCore/rendering/style/StyleFlexibleBoxData.cpp b/Source/WebCore/rendering/style/StyleFlexibleBoxData.cpp index de6fabdf0..62a7ee89e 100644 --- a/Source/WebCore/rendering/style/StyleFlexibleBoxData.cpp +++ b/Source/WebCore/rendering/style/StyleFlexibleBoxData.cpp @@ -31,40 +31,40 @@ namespace WebCore { StyleFlexibleBoxData::StyleFlexibleBoxData() - : m_widthPositiveFlex(RenderStyle::initialFlexboxWidthPositiveFlex()) - , m_widthNegativeFlex(RenderStyle::initialFlexboxWidthNegativeFlex()) - , m_heightPositiveFlex(RenderStyle::initialFlexboxHeightPositiveFlex()) - , m_heightNegativeFlex(RenderStyle::initialFlexboxHeightNegativeFlex()) + : m_positiveFlex(RenderStyle::initialPositiveFlex()) + , m_negativeFlex(RenderStyle::initialNegativeFlex()) + , m_preferredSize(RenderStyle::initialFlexPreferredSize()) , m_flexOrder(RenderStyle::initialFlexOrder()) , m_flexPack(RenderStyle::initialFlexPack()) , m_flexAlign(RenderStyle::initialFlexAlign()) , m_flexItemAlign(RenderStyle::initialFlexItemAlign()) , m_flexDirection(RenderStyle::initialFlexDirection()) , m_flexWrap(RenderStyle::initialFlexWrap()) + , m_flexLinePack(RenderStyle::initialFlexLinePack()) { } StyleFlexibleBoxData::StyleFlexibleBoxData(const StyleFlexibleBoxData& o) : RefCounted<StyleFlexibleBoxData>() - , m_widthPositiveFlex(o.m_widthPositiveFlex) - , m_widthNegativeFlex(o.m_widthNegativeFlex) - , m_heightPositiveFlex(o.m_heightPositiveFlex) - , m_heightNegativeFlex(o.m_heightNegativeFlex) + , m_positiveFlex(o.m_positiveFlex) + , m_negativeFlex(o.m_negativeFlex) + , m_preferredSize(o.m_preferredSize) , m_flexOrder(o.m_flexOrder) , m_flexPack(o.m_flexPack) , m_flexAlign(o.m_flexAlign) , m_flexItemAlign(o.m_flexItemAlign) , m_flexDirection(o.m_flexDirection) , m_flexWrap(o.m_flexWrap) + , m_flexLinePack(o.m_flexLinePack) { } bool StyleFlexibleBoxData::operator==(const StyleFlexibleBoxData& o) const { - return m_widthPositiveFlex == o.m_widthPositiveFlex && m_widthNegativeFlex == o.m_widthNegativeFlex - && m_heightPositiveFlex == o.m_heightPositiveFlex && m_heightNegativeFlex == o.m_heightNegativeFlex + return m_positiveFlex == o.m_positiveFlex && m_negativeFlex == o.m_negativeFlex && m_preferredSize == o.m_preferredSize && m_flexOrder == o.m_flexOrder && m_flexPack == o.m_flexPack && m_flexAlign == o.m_flexAlign - && m_flexItemAlign == o.m_flexItemAlign && m_flexDirection == o.m_flexDirection && m_flexWrap == o.m_flexWrap; + && m_flexItemAlign == o.m_flexItemAlign && m_flexDirection == o.m_flexDirection && m_flexWrap == o.m_flexWrap + && m_flexLinePack == o.m_flexLinePack; } } diff --git a/Source/WebCore/rendering/style/StyleFlexibleBoxData.h b/Source/WebCore/rendering/style/StyleFlexibleBoxData.h index c3bf5c39a..1ced849bc 100644 --- a/Source/WebCore/rendering/style/StyleFlexibleBoxData.h +++ b/Source/WebCore/rendering/style/StyleFlexibleBoxData.h @@ -26,6 +26,8 @@ #ifndef StyleFlexibleBoxData_h #define StyleFlexibleBoxData_h +#include "Length.h" + #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -42,10 +44,9 @@ public: return !(*this == o); } - float m_widthPositiveFlex; - float m_widthNegativeFlex; - float m_heightPositiveFlex; - float m_heightNegativeFlex; + float m_positiveFlex; + float m_negativeFlex; + Length m_preferredSize; int m_flexOrder; @@ -54,6 +55,7 @@ public: unsigned m_flexItemAlign : 3; // EFlexAlign unsigned m_flexDirection : 2; // EFlexDirection unsigned m_flexWrap : 2; // EFlexWrap + unsigned m_flexLinePack : 3; // EFlexLinePack private: StyleFlexibleBoxData(); diff --git a/Source/WebCore/rendering/style/StyleGeneratedImage.cpp b/Source/WebCore/rendering/style/StyleGeneratedImage.cpp index c52c74f6d..fd9949295 100644 --- a/Source/WebCore/rendering/style/StyleGeneratedImage.cpp +++ b/Source/WebCore/rendering/style/StyleGeneratedImage.cpp @@ -25,8 +25,8 @@ #include "StyleGeneratedImage.h" #include "CSSImageGeneratorValue.h" -#include "CSSStyleSelector.h" #include "RenderObject.h" +#include "StyleResolver.h" namespace WebCore { @@ -85,7 +85,7 @@ void StyleGeneratedImage::removeClient(RenderObject* renderer) PassRefPtr<Image> StyleGeneratedImage::image(RenderObject* renderer, const IntSize& size) const { - renderer->document()->styleSelector()->setStyle(renderer->style()); + renderer->document()->styleResolver()->setStyle(renderer->style()); return m_imageGeneratorValue->image(renderer, size); } diff --git a/Source/WebCore/rendering/style/StyleImage.h b/Source/WebCore/rendering/style/StyleImage.h index 0a5766b4f..1fc8e9759 100644 --- a/Source/WebCore/rendering/style/StyleImage.h +++ b/Source/WebCore/rendering/style/StyleImage.h @@ -62,10 +62,12 @@ public: virtual void removeClient(RenderObject*) = 0; virtual PassRefPtr<Image> image(RenderObject*, const IntSize&) const = 0; virtual WrappedImagePtr data() const = 0; + virtual float imageScaleFactor() const { return 1; } ALWAYS_INLINE bool isCachedImage() const { return m_isCachedImage; } ALWAYS_INLINE bool isPendingImage() const { return m_isPendingImage; } ALWAYS_INLINE bool isGeneratedImage() const { return m_isGeneratedImage; } + ALWAYS_INLINE bool isCachedImageSet() const { return m_isCachedImageSet; } static bool imagesEquivalent(StyleImage* image1, StyleImage* image2) { @@ -82,11 +84,13 @@ protected: : m_isCachedImage(false) , m_isPendingImage(false) , m_isGeneratedImage(false) + , m_isCachedImageSet(false) { } bool m_isCachedImage:1; bool m_isPendingImage:1; bool m_isGeneratedImage:1; + bool m_isCachedImageSet:1; }; } diff --git a/Source/WebCore/rendering/style/StylePendingImage.h b/Source/WebCore/rendering/style/StylePendingImage.h index 9aa0e20bf..6badc9238 100644 --- a/Source/WebCore/rendering/style/StylePendingImage.h +++ b/Source/WebCore/rendering/style/StylePendingImage.h @@ -27,6 +27,9 @@ #define StylePendingImage_h #include "CSSImageGeneratorValue.h" +#if ENABLE(CSS_IMAGE_SET) +#include "CSSImageSetValue.h" +#endif #include "CSSImageValue.h" #include "Image.h" #include "StyleImage.h" @@ -46,6 +49,9 @@ public: virtual PassRefPtr<CSSValue> cssValue() const { return m_value; } CSSImageValue* cssImageValue() const { return m_value->isImageValue() ? static_cast<CSSImageValue*>(m_value) : 0; } CSSImageGeneratorValue* cssImageGeneratorValue() const { return m_value->isImageGeneratorValue() ? static_cast<CSSImageGeneratorValue*>(m_value) : 0; } +#if ENABLE(CSS_IMAGE_SET) + CSSImageSetValue* cssImageSetValue() const { return m_value->isImageSetValue() ? static_cast<CSSImageSetValue*>(m_value) : 0; } +#endif virtual IntSize imageSize(const RenderObject*, float /*multiplier*/) const { return IntSize(); } virtual bool imageHasRelativeWidth() const { return false; } diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp index 529fc4eb8..c242dcc02 100644 --- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp +++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp @@ -22,7 +22,6 @@ #include "config.h" #include "StyleRareNonInheritedData.h" -#include "CSSStyleSelector.h" #include "ContentData.h" #include "RenderCounter.h" #include "RenderStyle.h" @@ -30,6 +29,7 @@ #include "StyleFilterData.h" #include "StyleTransformData.h" #include "StyleImage.h" +#include "StyleResolver.h" namespace WebCore { diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h index e95c55b60..ae72bd60a 100644 --- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h +++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h @@ -39,7 +39,6 @@ namespace WebCore { class AnimationList; -class CSSStyleSelector; class ShadowData; class StyleDeprecatedFlexibleBoxData; #if ENABLE(CSS_FILTERS) @@ -53,6 +52,7 @@ class StyleGridItemData; class StyleMarqueeData; class StyleMultiColData; class StyleReflection; +class StyleResolver; class StyleTransformData; class ContentData; diff --git a/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp index 8f8c86ea6..334f6eeb8 100644 --- a/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp @@ -27,6 +27,7 @@ #include "RenderSVGBlock.cpp" #include "RenderSVGContainer.cpp" +#include "RenderSVGEllipse.cpp" #include "RenderSVGForeignObject.cpp" #include "RenderSVGGradientStop.cpp" #include "RenderSVGHiddenContainer.cpp" @@ -55,7 +56,6 @@ #include "RenderSVGTextPath.cpp" #include "RenderSVGTransformableContainer.cpp" #include "RenderSVGViewportContainer.cpp" -#include "SVGImageBufferTools.cpp" #include "SVGInlineFlowBox.cpp" #include "SVGInlineTextBox.cpp" #include "SVGMarkerLayoutInfo.cpp" diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp index e16bfa33c..a1fd8321d 100644 --- a/Source/WebCore/rendering/svg/RenderSVGContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp @@ -40,6 +40,7 @@ namespace WebCore { RenderSVGContainer::RenderSVGContainer(SVGStyledElement* node) : RenderSVGModelObject(node) + , m_objectBoundingBoxValid(false) , m_needsBoundariesUpdate(true) { } @@ -150,10 +151,11 @@ void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, const LayoutP void RenderSVGContainer::updateCachedBoundaries() { m_objectBoundingBox = FloatRect(); + m_objectBoundingBoxValid = false; m_strokeBoundingBox = FloatRect(); m_repaintBoundingBox = FloatRect(); - SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_strokeBoundingBox, m_repaintBoundingBox); + SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_objectBoundingBoxValid, m_strokeBoundingBox, m_repaintBoundingBox); SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox); } diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.h b/Source/WebCore/rendering/svg/RenderSVGContainer.h index 84621f175..5be036638 100644 --- a/Source/WebCore/rendering/svg/RenderSVGContainer.h +++ b/Source/WebCore/rendering/svg/RenderSVGContainer.h @@ -42,6 +42,7 @@ public: virtual void paint(PaintInfo&, const LayoutPoint&); virtual void setNeedsBoundariesUpdate() { m_needsBoundariesUpdate = true; } virtual bool didTransformToRootUpdate() { return false; } + bool isObjectBoundingBoxValid() const { return m_objectBoundingBoxValid; } protected: virtual RenderObjectChildList* virtualChildren() { return children(); } @@ -76,6 +77,7 @@ protected: private: RenderObjectChildList m_children; FloatRect m_objectBoundingBox; + bool m_objectBoundingBoxValid; FloatRect m_strokeBoundingBox; FloatRect m_repaintBoundingBox; bool m_needsBoundariesUpdate : 1; @@ -83,15 +85,13 @@ private: inline RenderSVGContainer* toRenderSVGContainer(RenderObject* object) { - // Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this. - ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer"))); + ASSERT(!object || object->isSVGContainer()); return static_cast<RenderSVGContainer*>(object); } inline const RenderSVGContainer* toRenderSVGContainer(const RenderObject* object) { - // Note: isSVGContainer is also true for RenderSVGViewportContainer, which is not derived from this. - ASSERT(!object || (object->isSVGContainer() && strcmp(object->renderName(), "RenderSVGViewportContainer"))); + ASSERT(!object || object->isSVGContainer()); return static_cast<const RenderSVGContainer*>(object); } diff --git a/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp b/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp new file mode 100644 index 000000000..d147f6bfc --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2012 Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(SVG) +#include "RenderSVGEllipse.h" + +#include "SVGCircleElement.h" +#include "SVGEllipseElement.h" +#include "SVGNames.h" +#include "SVGStyledTransformableElement.h" + +namespace WebCore { + +RenderSVGEllipse::RenderSVGEllipse(SVGStyledTransformableElement* node) + : RenderSVGShape(node) +{ +} + +RenderSVGEllipse::~RenderSVGEllipse() +{ +} + +void RenderSVGEllipse::createShape() +{ + // Before creating a new object we need to clear the cached bounding box + // to avoid using garbage. + m_boundingBox = FloatRect(); + m_outerStrokeRect = FloatRect(); + m_center = FloatPoint(); + m_radii = FloatSize(); + + // Fallback to RenderSVGShape if shape has a non scaling stroke. + if (style()->svgStyle()->vectorEffect() == VE_NON_SCALING_STROKE) { + RenderSVGShape::createShape(); + setIsPaintingFallback(true); + return; + } + + calculateRadiiAndCenter(); + + // Spec: "A value of zero disables rendering of the element." + if (m_radii.width() <= 0 || m_radii.height() <= 0) + return; + + m_boundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height()); + m_outerStrokeRect = m_boundingBox; + if (style()->svgStyle()->hasStroke()) + m_outerStrokeRect.inflate(strokeWidth() / 2); +} + +void RenderSVGEllipse::calculateRadiiAndCenter() +{ + ASSERT(node()); + if (node()->hasTagName(SVGNames::circleTag)) { + + SVGCircleElement* circle = static_cast<SVGCircleElement*>(node()); + + SVGLengthContext lengthContext(circle); + float radius = circle->r().value(lengthContext); + m_radii = FloatSize(radius, radius); + m_center = FloatPoint(circle->cx().value(lengthContext), circle->cy().value(lengthContext)); + return; + } + + ASSERT(node()->hasTagName(SVGNames::ellipseTag)); + SVGEllipseElement* ellipse = static_cast<SVGEllipseElement*>(node()); + + SVGLengthContext lengthContext(ellipse); + m_radii = FloatSize(ellipse->rx().value(lengthContext), ellipse->ry().value(lengthContext)); + m_center = FloatPoint(ellipse->cx().value(lengthContext), ellipse->cy().value(lengthContext)); +} + +FloatRect RenderSVGEllipse::objectBoundingBox() const +{ + if (isPaintingFallback()) + return RenderSVGShape::objectBoundingBox(); + return m_boundingBox; +} + +FloatRect RenderSVGEllipse::strokeBoundingBox() const +{ + if (isPaintingFallback()) + return RenderSVGShape::strokeBoundingBox(); + return m_outerStrokeRect; +} + +void RenderSVGEllipse::fillShape(GraphicsContext* context) const +{ + if (isPaintingFallback()) { + RenderSVGShape::fillShape(context); + return; + } + context->fillEllipse(m_boundingBox); +} + +void RenderSVGEllipse::strokeShape(GraphicsContext* context) const +{ + if (!style()->svgStyle()->hasVisibleStroke()) + return; + if (isPaintingFallback()) { + RenderSVGShape::strokeShape(context); + return; + } + context->strokeEllipse(m_boundingBox); +} + +bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point) const +{ + if (isPaintingFallback()) + return RenderSVGShape::shapeDependentStrokeContains(point); + + float halfStrokeWidth = strokeWidth() / 2; + FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y()); + + // This works by checking if the point satisfies the ellipse equation, + // (x/rX)^2 + (y/rY)^2 <= 1, for the outer but not the inner stroke. + float xrXOuter = center.x() / (m_radii.width() + halfStrokeWidth); + float yrYOuter = center.y() / (m_radii.height() + halfStrokeWidth); + if (xrXOuter * xrXOuter + yrYOuter * yrYOuter > 1.0) + return false; + + float xrXInner = center.x() / (m_radii.width() - halfStrokeWidth); + float yrYInner = center.y() / (m_radii.height() - halfStrokeWidth); + return xrXInner * xrXInner + yrYInner * yrYInner >= 1.0; +} + +bool RenderSVGEllipse::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const +{ + if (isPaintingFallback()) + return RenderSVGShape::shapeDependentFillContains(point, fillRule); + + FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y()); + + // This works by checking if the point satisfies the ellipse equation. + // (x/rX)^2 + (y/rY)^2 <= 1 + float xrX = center.x() / m_radii.width(); + float yrY = center.y() / m_radii.height(); + return xrX * xrX + yrY * yrY <= 1.0; +} + +} + +#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGEllipse.h b/Source/WebCore/rendering/svg/RenderSVGEllipse.h new file mode 100644 index 000000000..76295c686 --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGEllipse.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderSVGEllipse_h +#define RenderSVGEllipse_h + +#if ENABLE(SVG) +#include "RenderSVGShape.h" +#include "SVGStyledTransformableElement.h" + +namespace WebCore { + +class RenderSVGEllipse : public RenderSVGShape { +public: + explicit RenderSVGEllipse(SVGStyledTransformableElement*); + virtual ~RenderSVGEllipse(); + +private: + virtual bool isSVGEllipse() const { return true; } + virtual const char* renderName() const { return "RenderSVGEllipse"; } + + virtual void createShape(); + virtual bool isEmpty() const { return hasPath() ? RenderSVGShape::isEmpty() : m_boundingBox.isEmpty(); }; + virtual void fillShape(GraphicsContext*) const; + virtual void strokeShape(GraphicsContext*) const; + virtual FloatRect objectBoundingBox() const; + virtual FloatRect strokeBoundingBox() const; + virtual bool shapeDependentStrokeContains(const FloatPoint&) const; + virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const; + void calculateRadiiAndCenter(); + +private: + FloatRect m_boundingBox; + FloatRect m_outerStrokeRect; + FloatPoint m_center; + FloatSize m_radii; +}; + +} + +#endif // ENABLE(SVG) +#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp index 676e8f4a7..2918fe3a9 100644 --- a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp @@ -26,6 +26,7 @@ #include "GraphicsContext.h" #include "LayoutRepainter.h" +#include "RenderObject.h" #include "RenderSVGResource.h" #include "RenderView.h" #include "SVGForeignObjectElement.h" @@ -165,13 +166,20 @@ void RenderSVGForeignObject::layout() bool RenderSVGForeignObject::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { + // Embedded content is drawn in the foreground phase. + if (hitTestAction != HitTestForeground) + return false; + FloatPoint localPoint = localTransform().inverse().mapPoint(pointInParent); // Early exit if local point is not contained in clipped viewport area if (SVGRenderSupport::isOverflowHidden(this) && !m_viewport.contains(localPoint)) return false; - return RenderBlock::nodeAtPoint(request, result, roundedLayoutPoint(localPoint), LayoutPoint(), hitTestAction); + // FOs establish a stacking context, so we need to hit-test all layers. + return RenderBlock::nodeAtPoint(request, result, roundedLayoutPoint(localPoint), LayoutPoint(), HitTestForeground) + || RenderBlock::nodeAtPoint(request, result, roundedLayoutPoint(localPoint), LayoutPoint(), HitTestFloat) + || RenderBlock::nodeAtPoint(request, result, roundedLayoutPoint(localPoint), LayoutPoint(), HitTestChildBlockBackgrounds); } bool RenderSVGForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint&, const LayoutPoint&, HitTestAction) @@ -180,7 +188,7 @@ bool RenderSVGForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, return false; } -void RenderSVGForeignObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool /* fixed */, bool /* useTransforms */, TransformState& transformState, bool* wasFixed) const +void RenderSVGForeignObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool /* fixed */, bool /* useTransforms */, TransformState& transformState, ApplyContainerFlipOrNot, bool* wasFixed) const { SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); } diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h index 905b488b6..4a1a8ac25 100644 --- a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h +++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h @@ -54,7 +54,7 @@ public: virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); virtual bool isSVGForeignObject() const { return true; } - virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&, bool* wasFixed = 0) const; + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } private: diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.cpp b/Source/WebCore/rendering/svg/RenderSVGInline.cpp index ea2746e79..ab8cc1a87 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInline.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInline.cpp @@ -79,7 +79,7 @@ void RenderSVGInline::computeFloatRectForRepaint(RenderBoxModelObject* repaintCo SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed); } -void RenderSVGInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool /* useTransforms */, bool /* fixed */, TransformState& transformState, bool* wasFixed) const +void RenderSVGInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool /* useTransforms */, bool /* fixed */, TransformState& transformState, ApplyContainerFlipOrNot, bool* wasFixed) const { SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); } diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.h b/Source/WebCore/rendering/svg/RenderSVGInline.h index 4344fb506..8aa4ab875 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInline.h +++ b/Source/WebCore/rendering/svg/RenderSVGInline.h @@ -47,7 +47,7 @@ public: virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const; virtual void computeFloatRectForRepaint(RenderBoxModelObject* repaintContainer, FloatRect&, bool fixed = false) const; - virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, bool* wasFixed = 0) const; + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; private: diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp index 591316291..09d446b7d 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp @@ -27,16 +27,16 @@ #include "RenderSVGInlineText.h" #include "CSSFontSelector.h" -#include "CSSStyleSelector.h" #include "FloatConversion.h" #include "FloatQuad.h" #include "RenderBlock.h" #include "RenderSVGRoot.h" #include "RenderSVGText.h" #include "Settings.h" -#include "SVGImageBufferTools.h" #include "SVGInlineTextBox.h" +#include "SVGRenderingContext.h" #include "SVGRootInlineBox.h" +#include "StyleResolver.h" #include "VisiblePosition.h" namespace WebCore { @@ -87,7 +87,8 @@ void RenderSVGInlineText::willBeDestroyed() if (affectedAttributes.isEmpty()) return; - textRenderer->rebuildLayoutAttributes(affectedAttributes); + if (!documentBeingDestroyed()) + textRenderer->rebuildLayoutAttributes(affectedAttributes); } void RenderSVGInlineText::setTextInternal(PassRefPtr<StringImpl> text) @@ -99,7 +100,7 @@ void RenderSVGInlineText::setTextInternal(PassRefPtr<StringImpl> text) // the RenderSVGInlineText objects, and thus needs to be rebuild. The latter will assure that the // SVGTextLayoutAttributes associated with the RenderSVGInlineText will be updated. if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) { - textRenderer->textDOMChanged(); + textRenderer->invalidateTextPositioningElements(); textRenderer->layoutAttributesChanged(this); } } @@ -147,13 +148,13 @@ LayoutRect RenderSVGInlineText::localCaretRect(InlineBox* box, int caretOffset, // Use the edge of the selection rect to determine the caret rect. if (static_cast<unsigned>(caretOffset) < textBox->start() + textBox->len()) { - IntRect rect = textBox->localSelectionRect(caretOffset, caretOffset + 1); - int x = box->isLeftToRightDirection() ? rect.x() : rect.maxX(); + LayoutRect rect = textBox->localSelectionRect(caretOffset, caretOffset + 1); + LayoutUnit x = box->isLeftToRightDirection() ? rect.x() : rect.maxX(); return LayoutRect(x, rect.y(), caretWidth, rect.height()); } - IntRect rect = textBox->localSelectionRect(caretOffset - 1, caretOffset); - int x = box->isLeftToRightDirection() ? rect.maxX() : rect.x(); + LayoutRect rect = textBox->localSelectionRect(caretOffset - 1, caretOffset); + LayoutUnit x = box->isLeftToRightDirection() ? rect.maxX() : rect.x(); return LayoutRect(x, rect.y(), caretWidth, rect.height()); } @@ -165,7 +166,7 @@ FloatRect RenderSVGInlineText::floatLinesBoundingBox() const return boundingBox; } -LayoutRect RenderSVGInlineText::linesBoundingBox() const +IntRect RenderSVGInlineText::linesBoundingBox() const { return enclosingIntRect(floatLinesBoundingBox()); } @@ -253,12 +254,12 @@ void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, c Document* document = renderer->document(); ASSERT(document); - CSSStyleSelector* styleSelector = document->styleSelector(); - ASSERT(styleSelector); + StyleResolver* styleResolver = document->styleResolver(); + ASSERT(styleResolver); // Alter font-size to the right on-screen value to avoid scaling the glyphs themselves, except when GeometricPrecision is specified AffineTransform ctm; - SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(renderer, ctm); + SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(renderer, ctm); scalingFactor = narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2)); if (scalingFactor == 1 || !scalingFactor || style->fontDescription().textRenderingMode() == GeometricPrecision) { scalingFactor = 1; @@ -269,10 +270,10 @@ void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, c FontDescription fontDescription(style->fontDescription()); // FIXME: We need to better handle the case when we compute very small fonts below (below 1pt). - fontDescription.setComputedSize(CSSStyleSelector::getComputedSizeFromSpecifiedSize(document, scalingFactor, fontDescription.isAbsoluteSize(), fontDescription.computedSize(), DoNotUseSmartMinimumForFontSize)); + fontDescription.setComputedSize(StyleResolver::getComputedSizeFromSpecifiedSize(document, scalingFactor, fontDescription.isAbsoluteSize(), fontDescription.computedSize(), DoNotUseSmartMinimumForFontSize)); scaledFont = Font(fontDescription, 0, 0); - scaledFont.update(styleSelector->fontSelector()); + scaledFont.update(styleResolver->fontSelector()); } } diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.h b/Source/WebCore/rendering/svg/RenderSVGInlineText.h index 6ac768c67..51378fd07 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.h +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.h @@ -59,7 +59,7 @@ private: virtual VisiblePosition positionForPoint(const LayoutPoint&); virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0); - virtual LayoutRect linesBoundingBox() const; + virtual IntRect linesBoundingBox() const; virtual InlineTextBox* createTextBox(); float m_scalingFactor; diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp index 3841336a5..48fd7d879 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp @@ -55,7 +55,7 @@ void RenderSVGModelObject::computeFloatRectForRepaint(RenderBoxModelObject* repa SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed); } -void RenderSVGModelObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool /* fixed */, bool /* useTransforms */, TransformState& transformState, bool* wasFixed) const +void RenderSVGModelObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool /* fixed */, bool /* useTransforms */, TransformState& transformState, ApplyContainerFlipOrNot, bool* wasFixed) const { SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); } diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.h b/Source/WebCore/rendering/svg/RenderSVGModelObject.h index 1582ff5fa..b9692fe1d 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.h +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.h @@ -58,7 +58,7 @@ public: virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const; virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; - virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, bool* wasFixed = 0) const; + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void updateFromElement(); diff --git a/Source/WebCore/rendering/svg/RenderSVGRect.cpp b/Source/WebCore/rendering/svg/RenderSVGRect.cpp index f3f020464..a200f3b11 100755 --- a/Source/WebCore/rendering/svg/RenderSVGRect.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGRect.cpp @@ -80,6 +80,14 @@ void RenderSVGRect::createShape() m_innerStrokeRect.inflate(-strokeWidth / 2); m_outerStrokeRect.inflate(strokeWidth / 2); } + + m_strokeBoundingRect = m_outerStrokeRect; + +#if USE(CG) + // CoreGraphics can inflate the stroke by 1px when drawing a rectangle with antialiasing disabled at non-integer coordinates, we need to compensate. + if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES) + m_strokeBoundingRect.inflate(1); +#endif } FloatRect RenderSVGRect::objectBoundingBox() const @@ -93,7 +101,7 @@ FloatRect RenderSVGRect::strokeBoundingBox() const { if (isPaintingFallback()) return RenderSVGShape::strokeBoundingBox(); - return m_outerStrokeRect; + return m_strokeBoundingRect; } void RenderSVGRect::fillShape(GraphicsContext* context) const @@ -119,6 +127,8 @@ void RenderSVGRect::fillShape(GraphicsContext* context) const void RenderSVGRect::strokeShape(GraphicsContext* context) const { + if (!style()->svgStyle()->hasVisibleStroke()) + return; if (!isPaintingFallback()) { context->strokeRect(m_boundingBox, strokeWidth()); return; diff --git a/Source/WebCore/rendering/svg/RenderSVGRect.h b/Source/WebCore/rendering/svg/RenderSVGRect.h index 37a116053..ab6eb2343 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRect.h +++ b/Source/WebCore/rendering/svg/RenderSVGRect.h @@ -56,6 +56,7 @@ private: FloatRect m_boundingBox; FloatRect m_innerStrokeRect; FloatRect m_outerStrokeRect; + FloatRect m_strokeBoundingRect; }; } diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp index ba20502f3..7339e2859 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp @@ -39,9 +39,9 @@ #include "RenderStyle.h" #include "SVGClipPathElement.h" #include "SVGElement.h" -#include "SVGImageBufferTools.h" #include "SVGNames.h" #include "SVGRenderSupport.h" +#include "SVGRenderingContext.h" #include "SVGResources.h" #include "SVGResourcesCache.h" #include "SVGStyledElement.h" @@ -155,7 +155,8 @@ bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, const FloatRect& objectBoundingBox, const FloatRect& repaintRect, GraphicsContext* context) { - if (!m_clipper.contains(object)) + bool missingClipperData = !m_clipper.contains(object); + if (missingClipperData) m_clipper.set(object, new ClipperData); bool shouldCreateClipData = false; @@ -168,10 +169,10 @@ bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, cons } AffineTransform absoluteTransform; - SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); + SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); if (shouldCreateClipData && !repaintRect.isEmpty()) { - if (!SVGImageBufferTools::createImageBuffer(repaintRect, absoluteTransform, clipperData->clipMaskImage, ColorSpaceDeviceRGB, Unaccelerated)) + if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, clipperData->clipMaskImage, ColorSpaceDeviceRGB, Unaccelerated)) return false; GraphicsContext* maskContext = clipperData->clipMaskImage->context(); @@ -201,7 +202,7 @@ bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, cons if (!clipperData->clipMaskImage) return false; - SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, repaintRect, clipperData->clipMaskImage); + SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, clipperData->clipMaskImage, missingClipperData); return true; } @@ -263,7 +264,7 @@ bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData // In the case of a <use> element, we obtained its renderere above, to retrieve its clipRule. // We have to pass the <use> renderer itself to renderSubtreeToImageBuffer() to apply it's x/y/transform/etc. values when rendering. // So if isUseElement is true, refetch the childNode->renderer(), as renderer got overriden above. - SVGImageBufferTools::renderSubtreeToImageBuffer(clipperData->clipMaskImage.get(), isUseElement ? childNode->renderer() : renderer, maskContentTransformation); + SVGRenderingContext::renderSubtreeToImageBuffer(clipperData->clipMaskImage.get(), isUseElement ? childNode->renderer() : renderer, maskContentTransformation); } frame()->view()->setPaintBehavior(oldBehavior); diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp index 2952442cf..3dba672dd 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp @@ -22,6 +22,7 @@ #if ENABLE(SVG) #include "RenderSVGResourceContainer.h" +#include "RenderSVGRoot.h" #include "RenderView.h" #include "SVGResourcesCache.h" #include "SVGStyledTransformableElement.h" @@ -53,7 +54,7 @@ void RenderSVGResourceContainer::layout() { // Invalidate all resources if our layout changed. if (everHadLayout() && selfNeedsLayout()) - removeAllClientsFromCache(); + RenderSVGRoot::addResourceForClientInvalidation(this); RenderSVGHiddenContainer::layout(); } diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp index 43ebee284..d5d792ded 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp @@ -43,8 +43,8 @@ #include "SVGFilter.h" #include "SVGFilterElement.h" #include "SVGFilterPrimitiveStandardAttributes.h" -#include "SVGImageBufferTools.h" #include "SVGNames.h" +#include "SVGRenderingContext.h" #include "SVGStyledElement.h" #include "SVGUnitTypes.h" @@ -165,7 +165,7 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, // Determine absolute transformation matrix for filter. AffineTransform absoluteTransform; - SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); + SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); if (!absoluteTransform.isInvertible()) return false; @@ -235,7 +235,7 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, OwnPtr<ImageBuffer> sourceGraphic; RenderingMode renderingMode = object->document()->page()->settings()->acceleratedFiltersEnabled() ? Accelerated : Unaccelerated; - if (!SVGImageBufferTools::createImageBuffer(drawingRegion, effectiveTransform, sourceGraphic, ColorSpaceLinearRGB, renderingMode)) { + if (!SVGRenderingContext::createImageBuffer(drawingRegion, effectiveTransform, sourceGraphic, ColorSpaceLinearRGB, renderingMode)) { ASSERT(!m_filter.contains(object)); filterData->savedContext = context; m_filter.set(object, filterData.leakPtr()); diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp index ead5510b5..f8f493db8 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp @@ -29,8 +29,8 @@ #include "GraphicsContext.h" #include "RenderSVGShape.h" #include "RenderSVGText.h" -#include "SVGImageBufferTools.h" #include "SVGRenderSupport.h" +#include "SVGRenderingContext.h" #include <wtf/UnusedParam.h> namespace WebCore { @@ -68,11 +68,11 @@ static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& con ASSERT(textRootBlock); AffineTransform absoluteTransform; - SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform); + SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform); FloatRect repaintRect = textRootBlock->repaintRectInLocalCoordinates(); OwnPtr<ImageBuffer> maskImage; - if (!SVGImageBufferTools::createImageBuffer(repaintRect, absoluteTransform, maskImage, ColorSpaceDeviceRGB, Unaccelerated)) + if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, maskImage, ColorSpaceDeviceRGB, Unaccelerated)) return false; GraphicsContext* maskImageContext = maskImage->context(); @@ -95,10 +95,10 @@ static inline AffineTransform clipToTextMask(GraphicsContext* context, ASSERT(textRootBlock); AffineTransform absoluteTransform; - SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform); + SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform); targetRect = textRootBlock->repaintRectInLocalCoordinates(); - SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, targetRect, imageBuffer); + SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, targetRect, imageBuffer, false); AffineTransform matrix; if (boundingBoxMode) { @@ -140,7 +140,7 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle* if (gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && objectBoundingBox.isEmpty()) return false; - OwnPtr<GradientData>& gradientData = m_gradientMap.add(object, nullptr).first->second; + OwnPtr<GradientData>& gradientData = m_gradientMap.add(object, nullptr).iterator->second; if (!gradientData) gradientData = adoptPtr(new GradientData); diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp index dc0755dd9..784559e21 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp @@ -26,6 +26,7 @@ #include "GraphicsContext.h" #include "RenderSVGContainer.h" +#include "RenderSVGRoot.h" #include "SVGElement.h" #include "SVGMarkerElement.h" #include "SVGRenderSupport.h" @@ -49,7 +50,7 @@ void RenderSVGResourceMarker::layout() { // Invalidate all resources if our layout changed. if (everHadLayout() && selfNeedsLayout()) - removeAllClientsFromCache(); + RenderSVGRoot::addResourceForClientInvalidation(this); // RenderSVGHiddenContainer overwrites layout(). We need the // layouting of RenderSVGContainer for calculating local diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp index bf5954947..e6eb6afc2 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp @@ -32,12 +32,11 @@ #include "IntRect.h" #include "RenderSVGResource.h" #include "SVGElement.h" -#include "SVGImageBufferTools.h" #include "SVGMaskElement.h" +#include "SVGRenderingContext.h" #include "SVGStyledElement.h" #include "SVGUnitTypes.h" -#include <wtf/ByteArray.h> #include <wtf/UnusedParam.h> #include <wtf/Vector.h> @@ -86,13 +85,14 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, ASSERT(context); ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); - if (!m_masker.contains(object)) + bool missingMaskerData = !m_masker.contains(object); + if (missingMaskerData) m_masker.set(object, new MaskerData); MaskerData* maskerData = m_masker.get(object); AffineTransform absoluteTransform; - SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); + SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); FloatRect repaintRect = object->repaintRectInLocalCoordinates(); @@ -105,7 +105,7 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, const SVGRenderStyle* svgStyle = style()->svgStyle(); ASSERT(svgStyle); ColorSpace colorSpace = svgStyle->colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB; - if (!SVGImageBufferTools::createImageBuffer(repaintRect, absoluteTransform, maskerData->maskImage, colorSpace, Unaccelerated)) + if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, maskerData->maskImage, colorSpace, Unaccelerated)) return false; if (!drawContentIntoMaskImage(maskerData, colorSpace, maskElement, object)) { @@ -116,7 +116,7 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, if (!maskerData->maskImage) return false; - SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, repaintRect, maskerData->maskImage); + SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, maskerData->maskImage, missingMaskerData); return true; } @@ -144,7 +144,7 @@ bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, C RenderStyle* style = renderer->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; - SVGImageBufferTools::renderSubtreeToImageBuffer(maskerData->maskImage.get(), renderer, maskContentTransformation); + SVGRenderingContext::renderSubtreeToImageBuffer(maskerData->maskImage.get(), renderer, maskContentTransformation); } #if !USE(CG) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp index f727bb062..4dc501b80 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp @@ -27,8 +27,8 @@ #include "GraphicsContext.h" #include "PatternAttributes.h" #include "RenderSVGRoot.h" -#include "SVGImageBufferTools.h" #include "SVGRenderSupport.h" +#include "SVGRenderingContext.h" namespace WebCore { @@ -83,7 +83,7 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* if (m_attributes.patternUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && objectBoundingBox.isEmpty()) return false; - OwnPtr<PatternData>& patternData = m_patternMap.add(object, nullptr).first->second; + OwnPtr<PatternData>& patternData = m_patternMap.add(object, nullptr).iterator->second; if (!patternData) patternData = adoptPtr(new PatternData); @@ -99,10 +99,10 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* return false; AffineTransform absoluteTransformIgnoringRotation; - SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransformIgnoringRotation); + SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransformIgnoringRotation); // Ignore 2D rotation, as it doesn't affect the size of the tile. - SVGImageBufferTools::clear2DRotation(absoluteTransformIgnoringRotation); + SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation); FloatRect absoluteTileBoundaries = absoluteTransformIgnoringRotation.mapRect(tileBoundaries); FloatRect clampedAbsoluteTileBoundaries; @@ -232,11 +232,11 @@ PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternA const AffineTransform& tileImageTransform, FloatRect& clampedAbsoluteTileBoundaries) const { - clampedAbsoluteTileBoundaries = SVGImageBufferTools::clampedAbsoluteTargetRect(absoluteTileBoundaries); + clampedAbsoluteTileBoundaries = SVGRenderingContext::clampedAbsoluteTargetRect(absoluteTileBoundaries); OwnPtr<ImageBuffer> tileImage; - if (!SVGImageBufferTools::createImageBufferForPattern(absoluteTileBoundaries, clampedAbsoluteTileBoundaries, tileImage, ColorSpaceDeviceRGB, Unaccelerated)) + if (!SVGRenderingContext::createImageBufferForPattern(absoluteTileBoundaries, clampedAbsoluteTileBoundaries, tileImage, ColorSpaceDeviceRGB, Unaccelerated)) return nullptr; GraphicsContext* tileImageContext = tileImage->context(); @@ -260,7 +260,7 @@ PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternA continue; if (node->renderer()->needsLayout()) return nullptr; - SVGImageBufferTools::renderSubtreeToImageBuffer(tileImage.get(), node->renderer(), contentTransformation); + SVGRenderingContext::renderSubtreeToImageBuffer(tileImage.get(), node->renderer(), contentTransformation); } return tileImage.release(); diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp index b99701d81..67b8a714b 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp @@ -36,6 +36,7 @@ #include "RenderPart.h" #include "RenderSVGContainer.h" #include "RenderSVGResource.h" +#include "RenderSVGResourceContainer.h" #include "RenderView.h" #include "SVGLength.h" #include "SVGRenderingContext.h" @@ -56,6 +57,7 @@ namespace WebCore { RenderSVGRoot::RenderSVGRoot(SVGStyledElement* node) : RenderReplaced(node) + , m_objectBoundingBoxValid(false) , m_isLayoutSizeChanged(false) , m_needsBoundariesOrTransformUpdate(true) { @@ -87,9 +89,9 @@ void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, d // resolving both values to user units. if (intrinsicWidthAttribute.isFixed() || intrinsicHeightAttribute.isFixed()) { if (intrinsicWidthAttribute.isFixed()) - intrinsicSize.setWidth(intrinsicWidthAttribute.calcFloatValue(0)); + intrinsicSize.setWidth(floatValueForLength(intrinsicWidthAttribute, 0)); if (intrinsicHeightAttribute.isFixed()) - intrinsicSize.setHeight(intrinsicHeightAttribute.calcFloatValue(0)); + intrinsicSize.setHeight(floatValueForLength(intrinsicHeightAttribute, 0)); if (!intrinsicSize.isEmpty()) intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); return; @@ -151,9 +153,9 @@ bool RenderSVGRoot::isEmbeddedThroughFrameContainingSVGDocument() const return frame->document()->isSVGDocument(); } -static inline LayoutUnit resolveLengthAttributeForSVG(const Length& length, float scale, float maxSize) +static inline LayoutUnit resolveLengthAttributeForSVG(const Length& length, float scale, float maxSize, RenderView* renderView) { - return static_cast<LayoutUnit>(length.calcValue(maxSize) * (length.isFixed() ? scale : 1)); + return static_cast<LayoutUnit>(valueForLength(length, maxSize, renderView) * (length.isFixed() ? scale : 1)); } LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(bool includeMaxWidth) const @@ -169,7 +171,7 @@ LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(bool includeMaxWidth) cons return RenderReplaced::computeReplacedLogicalWidth(includeMaxWidth); if (svg->widthAttributeEstablishesViewport()) - return resolveLengthAttributeForSVG(svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties), style()->effectiveZoom(), containingBlock()->availableLogicalWidth()); + return resolveLengthAttributeForSVG(svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties), style()->effectiveZoom(), containingBlock()->availableLogicalWidth(), view()); // Only SVGs embedded in <object> reach this point. ASSERT(isEmbeddedThroughFrameContainingSVGDocument()); @@ -200,7 +202,7 @@ LayoutUnit RenderSVGRoot::computeReplacedLogicalHeight() const } else RenderBlock::removePercentHeightDescendant(const_cast<RenderSVGRoot*>(this)); - return resolveLengthAttributeForSVG(height, style()->effectiveZoom(), containingBlock()->availableLogicalHeight()); + return resolveLengthAttributeForSVG(height, style()->effectiveZoom(), containingBlock()->availableLogicalHeight(), view()); } // Only SVGs embedded in <object> reach this point. @@ -212,6 +214,8 @@ void RenderSVGRoot::layout() { ASSERT(needsLayout()); + m_resourcesNeedingToInvalidateClients.clear(); + // Arbitrary affine transforms are incompatible with LayoutState. LayoutStateDisabler layoutStateDisabler(view()); @@ -227,6 +231,16 @@ void RenderSVGRoot::layout() m_isLayoutSizeChanged = needsLayout || (svg->hasRelativeLengths() && oldSize != size()); SVGRenderSupport::layoutChildren(this, needsLayout || SVGRenderSupport::filtersForceContainerLayout(this)); + if (!m_resourcesNeedingToInvalidateClients.isEmpty()) { + // Invalidate resource clients, which may mark some nodes for layout. + HashSet<RenderSVGResourceContainer*>::iterator end = m_resourcesNeedingToInvalidateClients.end(); + for (HashSet<RenderSVGResourceContainer*>::iterator it = m_resourcesNeedingToInvalidateClients.begin(); it != end; ++it) + (*it)->removeAllClientsFromCache(); + + m_isLayoutSizeChanged = false; + SVGRenderSupport::layoutChildren(this, false); + } + // At this point LayoutRepainter already grabbed the old bounds, // recalculate them now so repaintAfterLayout() uses the new bounds. if (m_needsBoundariesOrTransformUpdate) { @@ -239,10 +253,10 @@ void RenderSVGRoot::layout() setNeedsLayout(false); } -void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& adjustedPaintOffset) +void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. - if (borderBoxRect().isEmpty()) + if (pixelSnappedBorderBoxRect().isEmpty()) return; // Don't paint, if the context explicitely disabled it. @@ -271,10 +285,11 @@ void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& adjus childPaintInfo.context->save(); // Apply initial viewport clip - not affected by overflow handling - childPaintInfo.context->clip(overflowClipRect(adjustedPaintOffset, paintInfo.renderRegion)); + childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset, paintInfo.renderRegion))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. + IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x() - x(), adjustedPaintOffset.y() - y()) * localToParentTransform()); SVGRenderingContext renderingContext; @@ -354,7 +369,7 @@ void RenderSVGRoot::computeFloatRectForRepaint(RenderBoxModelObject* repaintCont repaintRect = m_localToBorderBoxTransform.mapRect(repaintRect); // Apply initial viewport clip - not affected by overflow settings - repaintRect.intersect(borderBoxRect()); + repaintRect.intersect(pixelSnappedBorderBoxRect()); const SVGRenderStyle* svgStyle = style()->svgStyle(); if (const ShadowData* shadow = svgStyle->shadow()) @@ -365,23 +380,25 @@ void RenderSVGRoot::computeFloatRectForRepaint(RenderBoxModelObject* repaintCont repaintRect = rect; } -void RenderSVGRoot::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, bool* wasFixed) const +// This method expects local CSS box coordinates. +// Callers with local SVG viewport coordinates should first apply the localToBorderBoxTransform +// to convert from SVG viewport coordinates to local CSS box coordinates. +void RenderSVGRoot::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, ApplyContainerFlipOrNot, bool* wasFixed) const { ASSERT(!fixed); // We should have no fixed content in the SVG rendering tree. ASSERT(useTransforms); // mapping a point through SVG w/o respecting trasnforms is useless. - // Transform to our border box and let RenderBox transform the rest of the way. - transformState.applyTransform(m_localToBorderBoxTransform); - RenderReplaced::mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, wasFixed); + RenderReplaced::mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, ApplyContainerFlip, wasFixed); } void RenderSVGRoot::updateCachedBoundaries() { m_objectBoundingBox = FloatRect(); + m_objectBoundingBoxValid = false; m_strokeBoundingBox = FloatRect(); m_repaintBoundingBox = FloatRect(); - SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_strokeBoundingBox, m_repaintBoundingBox); + SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_objectBoundingBoxValid, m_strokeBoundingBox, m_repaintBoundingBox); SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox); m_repaintBoundingBox.inflate(borderAndPaddingWidth()); } @@ -428,6 +445,24 @@ bool RenderSVGRoot::hasRelativeDimensions() const return svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties).isPercent() || svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties).isPercent(); } +bool RenderSVGRoot::hasRelativeLogicalHeight() const +{ + SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); + ASSERT(svg); + + return svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties).isPercent(); +} + +void RenderSVGRoot::addResourceForClientInvalidation(RenderSVGResourceContainer* resource) +{ + RenderObject* svgRoot = resource->parent(); + while (svgRoot && !svgRoot->isSVGRoot()) + svgRoot = svgRoot->parent(); + if (!svgRoot) + return; + static_cast<RenderSVGRoot*>(svgRoot)->m_resourcesNeedingToInvalidateClients.add(resource); +} + } #endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.h b/Source/WebCore/rendering/svg/RenderSVGRoot.h index adc1884e4..c334afbe6 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRoot.h +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.h @@ -54,6 +54,14 @@ public: void setContainerSize(const IntSize& containerSize) { m_containerSize = containerSize; } virtual bool hasRelativeDimensions() const; + virtual bool hasRelativeLogicalHeight() const; + + // localToBorderBoxTransform maps local SVG viewport coordinates to local CSS box coordinates. + const AffineTransform& localToBorderBoxTransform() const { return m_localToBorderBoxTransform; } + + // The flag is cleared at the beginning of each layout() pass. Elements then call this + // method during layout when they are invalidated by a filter. + static void addResourceForClientInvalidation(RenderSVGResourceContainer*); private: virtual RenderObjectChildList* virtualChildren() { return children(); } @@ -86,7 +94,7 @@ private: virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const; virtual void computeFloatRectForRepaint(RenderBoxModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const; - virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, bool* wasFixed = 0) const; + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; virtual bool canBeSelectionLeaf() const { return false; } virtual bool canHaveChildren() const { return true; } @@ -96,10 +104,12 @@ private: RenderObjectChildList m_children; IntSize m_containerSize; FloatRect m_objectBoundingBox; + bool m_objectBoundingBoxValid; FloatRect m_strokeBoundingBox; FloatRect m_repaintBoundingBox; mutable AffineTransform m_localToParentTransform; AffineTransform m_localToBorderBoxTransform; + HashSet<RenderSVGResourceContainer*> m_resourcesNeedingToInvalidateClients; bool m_isLayoutSizeChanged : 1; bool m_needsBoundariesOrTransformUpdate : 1; }; diff --git a/Source/WebCore/rendering/svg/RenderSVGShape.cpp b/Source/WebCore/rendering/svg/RenderSVGShape.cpp index c438d30b0..c3481ce40 100755 --- a/Source/WebCore/rendering/svg/RenderSVGShape.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGShape.cpp @@ -62,13 +62,6 @@ RenderSVGShape::RenderSVGShape(SVGStyledTransformableElement* node) { } -RenderSVGShape::RenderSVGShape(SVGStyledTransformableElement* node, Path* path, bool isFillFallback) - : RenderSVGModelObject(node) - , m_path(adoptPtr(path)) - , m_fillFallback(isFillFallback) -{ -} - RenderSVGShape::~RenderSVGShape() { } @@ -101,7 +94,8 @@ FloatRect RenderSVGShape::objectBoundingBox() const void RenderSVGShape::strokeShape(GraphicsContext* context) const { - context->strokePath(path()); + if (style()->svgStyle()->hasVisibleStroke()) + context->strokePath(path()); } bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point) const @@ -129,7 +123,7 @@ bool RenderSVGShape::fillContains(const FloatPoint& point, bool requiresFill, co bool RenderSVGShape::strokeContains(const FloatPoint& point, bool requiresStroke) { - if (!m_strokeAndMarkerBoundingBox.contains(point)) + if (!strokeBoundingBox().contains(point)) return false; Color fallbackColor; @@ -152,7 +146,7 @@ bool RenderSVGShape::strokeContains(const FloatPoint& point, bool requiresStroke } if (!svgStyle->strokeDashArray().isEmpty() || svgStyle->strokeMiterLimit() != svgStyle->initialStrokeMiterLimit() - || svgStyle->joinStyle() != svgStyle->initialJoinStyle() || svgStyle->capStyle() != svgStyle->initialCapStyle() || static_cast<SVGElement*>(node())->isStyled()) { + || svgStyle->joinStyle() != svgStyle->initialJoinStyle() || svgStyle->capStyle() != svgStyle->initialCapStyle()) { if (!m_path) RenderSVGShape::createShape(); return RenderSVGShape::shapeDependentStrokeContains(point); @@ -272,6 +266,8 @@ void RenderSVGShape::strokePath(RenderStyle* style, GraphicsContext* context, Pa const Color& fallbackColor, bool nonScalingStroke, const AffineTransform& nonScalingStrokeTransform, int applyMode) { + if (!style->svgStyle()->hasVisibleStroke()) + return; Path* usePath = path; if (nonScalingStroke) { usePath = nonScalingStrokePath(path, nonScalingStrokeTransform); @@ -318,7 +314,7 @@ void RenderSVGShape::fillAndStrokePath(GraphicsContext* context) } -void RenderSVGShape::paint(PaintInfo& paintInfo, const IntPoint&) +void RenderSVGShape::paint(PaintInfo& paintInfo, const LayoutPoint&) { if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || isEmpty()) return; diff --git a/Source/WebCore/rendering/svg/RenderSVGShape.h b/Source/WebCore/rendering/svg/RenderSVGShape.h index 934a05d39..ab9b1cb5a 100644 --- a/Source/WebCore/rendering/svg/RenderSVGShape.h +++ b/Source/WebCore/rendering/svg/RenderSVGShape.h @@ -144,7 +144,6 @@ private: bool m_needsShapeUpdate : 1; bool m_needsTransformUpdate : 1; bool m_fillFallback : 1; - bool m_strokeContainsFallBack : 1; }; inline RenderSVGShape* toRenderSVGShape(RenderObject* object) diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp index d9cdeccdf..f512ab87b 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp @@ -6,6 +6,7 @@ * Copyright (C) 2008 Rob Buis <buis@kde.org> * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. + * Copyright (C) 2012 Google Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -104,7 +105,7 @@ void RenderSVGText::computeFloatRectForRepaint(RenderBoxModelObject* repaintCont SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed); } -void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool /* fixed */, bool /* useTransforms */, TransformState& transformState, bool* wasFixed) const +void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool /* fixed */, bool /* useTransforms */, TransformState& transformState, ApplyContainerFlipOrNot, bool* wasFixed) const { SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); } @@ -177,10 +178,12 @@ void RenderSVGText::layoutAttributesWillBeDestroyed(RenderSVGInlineText* text, V affectedAttributes.append(next); } -void RenderSVGText::textDOMChanged() +void RenderSVGText::invalidateTextPositioningElements() { - if (m_needsPositioningValuesUpdate) - return; + // Clear the text positioning elements. This should be called when either the children + // of a DOM text element have changed, or the length of the text in any child element + // has changed. Failure to clear may leave us with invalid elements, as other code paths + // do not always cause the position elements to be marked invalid before use. m_layoutAttributesBuilder.clearTextPositioningElements(); } @@ -330,7 +333,7 @@ void RenderSVGText::paint(PaintInfo& paintInfo, const LayoutPoint&) PaintInfo blockInfo(paintInfo); GraphicsContextStateSaver stateSaver(*blockInfo.context); blockInfo.applyTransform(localToParentTransform()); - RenderBlock::paint(blockInfo, IntPoint()); + RenderBlock::paint(blockInfo, LayoutPoint()); } FloatRect RenderSVGText::strokeBoundingBox() const diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h index 7b0b5efa8..5665b4442 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.h +++ b/Source/WebCore/rendering/svg/RenderSVGText.h @@ -49,7 +49,10 @@ public: bool needsReordering() const { return m_needsReordering; } - void textDOMChanged(); + // Call this method when either the children of a DOM text element have changed, or the length of + // the text in any child element has changed. + void invalidateTextPositioningElements(); + void layoutAttributesChanged(RenderObject*); void layoutAttributesWillBeDestroyed(RenderSVGInlineText*, Vector<SVGTextLayoutAttributes*>& affectedAttributes); void rebuildLayoutAttributes(bool performFullRebuild = false); @@ -75,7 +78,7 @@ private: virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect&, bool fixed = false) const; virtual void computeFloatRectForRepaint(RenderBoxModelObject* repaintContainer, FloatRect&, bool fixed = false) const; - virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, bool* wasFixed = 0) const; + virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); virtual FloatRect objectBoundingBox() const { return frameRect(); } diff --git a/Source/WebCore/rendering/svg/SVGImageBufferTools.cpp b/Source/WebCore/rendering/svg/SVGImageBufferTools.cpp deleted file mode 100644 index 899550055..000000000 --- a/Source/WebCore/rendering/svg/SVGImageBufferTools.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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 "SVGImageBufferTools.h" - -#include "FrameView.h" -#include "GraphicsContext.h" -#include "RenderObject.h" -#include "RenderSVGContainer.h" -#include "RenderSVGRoot.h" - -static int kMaxImageBufferSize = 4096; - -namespace WebCore { - -static AffineTransform& currentContentTransformation() -{ - DEFINE_STATIC_LOCAL(AffineTransform, s_currentContentTransformation, ()); - return s_currentContentTransformation; -} - -void SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform) -{ - const RenderObject* current = renderer; - ASSERT(current); - - absoluteTransform = currentContentTransformation(); - while (current) { - absoluteTransform = current->localToParentTransform() * absoluteTransform; - if (current->isSVGRoot()) - break; - current = current->parent(); - } -} - -bool SVGImageBufferTools::createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, OwnPtr<ImageBuffer>& imageBuffer, ColorSpace colorSpace, RenderingMode renderingMode) -{ - IntRect paintRect = calculateImageBufferRect(targetRect, absoluteTransform); - // Don't create empty ImageBuffers. - if (paintRect.isEmpty()) - return false; - - IntSize clampedSize = clampedAbsoluteSize(paintRect.size()); - OwnPtr<ImageBuffer> image = ImageBuffer::create(clampedSize, 1, colorSpace, renderingMode); - if (!image) - return false; - - GraphicsContext* imageContext = image->context(); - ASSERT(imageContext); - - // This is done in absolute coordinates. - imageContext->translate(-paintRect.x(), -paintRect.y()); - - imageContext->concatCTM(absoluteTransform); - - // This happens in local coordinates. - imageContext->scale(FloatSize(static_cast<float>(clampedSize.width()) / paintRect.width(), - static_cast<float>(clampedSize.height()) / paintRect.height())); - - imageBuffer = image.release(); - return true; -} - -bool SVGImageBufferTools::createImageBufferForPattern(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>& imageBuffer, ColorSpace colorSpace, RenderingMode renderingMode) -{ - IntSize imageSize(roundedIntSize(clampedAbsoluteTargetRect.size())); - IntSize unclampedImageSize(roundedIntSize(absoluteTargetRect.size())); - - // Don't create empty ImageBuffers. - if (imageSize.isEmpty()) - return false; - - OwnPtr<ImageBuffer> image = ImageBuffer::create(imageSize, 1, colorSpace, renderingMode); - if (!image) - return false; - - GraphicsContext* imageContext = image->context(); - ASSERT(imageContext); - - // Compensate rounding effects, as the absolute target rect is using floating-point numbers and the image buffer size is integer. - imageContext->scale(FloatSize(unclampedImageSize.width() / absoluteTargetRect.width(), unclampedImageSize.height() / absoluteTargetRect.height())); - - imageBuffer = image.release(); - return true; -} - -void SVGImageBufferTools::renderSubtreeToImageBuffer(ImageBuffer* image, RenderObject* item, const AffineTransform& subtreeContentTransformation) -{ - ASSERT(item); - ASSERT(image); - ASSERT(image->context()); - - PaintInfo info(image->context(), PaintInfo::infiniteRect(), PaintPhaseForeground, 0, 0, 0, 0); - - AffineTransform& contentTransformation = currentContentTransformation(); - AffineTransform savedContentTransformation = contentTransformation; - contentTransformation = subtreeContentTransformation * contentTransformation; - - ASSERT(!item->needsLayout()); - item->paint(info, IntPoint()); - - contentTransformation = savedContentTransformation; -} - -void SVGImageBufferTools::clipToImageBuffer(GraphicsContext* context, const AffineTransform& absoluteTransform, const FloatRect& targetRect, OwnPtr<ImageBuffer>& imageBuffer) -{ - ASSERT(context); - ASSERT(imageBuffer); - - FloatRect absoluteTargetRect = calculateImageBufferRect(targetRect, absoluteTransform); - - // The mask image has been created in the absolute coordinate space, as the image should not be scaled. - // So the actual masking process has to be done in the absolute coordinate space as well. - context->concatCTM(absoluteTransform.inverse()); - context->clipToImageBuffer(imageBuffer.get(), absoluteTargetRect); - context->concatCTM(absoluteTransform); - - // When nesting resources, with objectBoundingBox as content unit types, there's no use in caching the - // resulting image buffer as the parent resource already caches the result. - if (!currentContentTransformation().isIdentity()) - imageBuffer.clear(); -} - -FloatRect SVGImageBufferTools::clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect) -{ - const FloatSize maxImageBufferSize(kMaxImageBufferSize, kMaxImageBufferSize); - return FloatRect(absoluteTargetRect.location(), absoluteTargetRect.size().shrunkTo(maxImageBufferSize)); -} - -IntSize SVGImageBufferTools::clampedAbsoluteSize(const IntSize& absoluteSize) -{ - const IntSize maxImageBufferSize(kMaxImageBufferSize, kMaxImageBufferSize); - return absoluteSize.shrunkTo(maxImageBufferSize); -} - -void SVGImageBufferTools::clear2DRotation(AffineTransform& transform) -{ - AffineTransform::DecomposedType decomposition; - transform.decompose(decomposition); - decomposition.angle = 0; - transform.recompose(decomposition); -} - -} - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGImageBufferTools.h b/Source/WebCore/rendering/svg/SVGImageBufferTools.h deleted file mode 100644 index dce80cc96..000000000 --- a/Source/WebCore/rendering/svg/SVGImageBufferTools.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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 SVGImageBufferTools_h -#define SVGImageBufferTools_h - -#if ENABLE(SVG) -#include "ImageBuffer.h" -#include "IntRect.h" -#include <wtf/Noncopyable.h> - -namespace WebCore { - -class AffineTransform; -class FloatRect; -class FloatSize; -class GraphicsContext; -class RenderObject; - -class SVGImageBufferTools { - WTF_MAKE_NONCOPYABLE(SVGImageBufferTools); - -public: - static bool createImageBuffer(const FloatRect& paintRect, const AffineTransform& absoluteTransform, OwnPtr<ImageBuffer>&, ColorSpace, RenderingMode); - // Patterns need a different float-to-integer coordinate mapping. - static bool createImageBufferForPattern(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>&, ColorSpace, RenderingMode); - - static void renderSubtreeToImageBuffer(ImageBuffer*, RenderObject*, const AffineTransform&); - static void clipToImageBuffer(GraphicsContext*, const AffineTransform& absoluteTransform, const FloatRect& targetRect, OwnPtr<ImageBuffer>&); - - static void calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject*, AffineTransform& absoluteTransform); - static IntSize clampedAbsoluteSize(const IntSize&); - static FloatRect clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect); - static void clear2DRotation(AffineTransform&); - - static IntRect calculateImageBufferRect(const FloatRect& targetRect, const AffineTransform& absoluteTransform) - { - return enclosingIntRect(absoluteTransform.mapRect(targetRect)); - } - -private: - SVGImageBufferTools() { } - ~SVGImageBufferTools() { } -}; - -} - -#endif -#endif diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp index c4b60df08..27ba5fbce 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp @@ -35,7 +35,7 @@ #include "RenderSVGInlineText.h" #include "RenderSVGResource.h" #include "RenderSVGResourceSolidColor.h" -#include "SVGImageBufferTools.h" +#include "SVGRenderingContext.h" #include "SVGResourcesCache.h" #include "SVGRootInlineBox.h" #include "SVGTextRunRenderingContext.h" @@ -53,6 +53,14 @@ SVGInlineTextBox::SVGInlineTextBox(RenderObject* object) { } +void SVGInlineTextBox::dirtyLineBoxes() +{ + InlineTextBox::dirtyLineBoxes(); + + // Clear the now stale text fragments + clearTextFragments(); +} + int SVGInlineTextBox::offsetForPosition(float, bool) const { // SVG doesn't use the standard offset <-> position selection system, as it's not suitable for SVGs complex needs. @@ -120,13 +128,13 @@ FloatRect SVGInlineTextBox::selectionRectForTextFragment(const SVGTextFragment& return selectionRect; } -IntRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPosition) +LayoutRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPosition) { int boxStart = start(); startPosition = max(startPosition - boxStart, 0); endPosition = min(endPosition - boxStart, static_cast<int>(len())); if (startPosition >= endPosition) - return IntRect(); + return LayoutRect(); RenderText* text = textRenderer(); ASSERT(text); @@ -266,7 +274,7 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni ASSERT(svgStyle); bool hasFill = svgStyle->hasFill(); - bool hasStroke = svgStyle->hasStroke(); + bool hasVisibleStroke = svgStyle->hasVisibleStroke(); RenderStyle* selectionStyle = style; if (hasSelection) { @@ -277,15 +285,15 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni if (!hasFill) hasFill = svgSelectionStyle->hasFill(); - if (!hasStroke) - hasStroke = svgSelectionStyle->hasStroke(); + if (!hasVisibleStroke) + hasVisibleStroke = svgSelectionStyle->hasVisibleStroke(); } else selectionStyle = style; } if (textRenderer->frame() && textRenderer->frame()->view() && textRenderer->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask) { hasFill = true; - hasStroke = false; + hasVisibleStroke = false; } AffineTransform fragmentTransform; @@ -313,7 +321,7 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni } // Stroke text - if (hasStroke) { + if (hasVisibleStroke) { m_paintingResourceMode = ApplyToStrokeMode | ApplyToTextMode; paintText(paintInfo.context, style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly); } @@ -419,7 +427,7 @@ TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFrag , 0 /* padding, only relevant for justified text, not relevant for SVG */ , TextRun::AllowTrailingExpansion , direction() - , m_dirOverride || style->rtlOrdering() == VisualOrder /* directionalOverride */); + , dirOverride() || style->rtlOrdering() == VisualOrder /* directionalOverride */); if (textRunNeedsRenderingContext(style->font())) run.setRenderingContext(SVGTextRunRenderingContext::create(text)); @@ -518,14 +526,14 @@ void SVGInlineTextBox::paintDecoration(GraphicsContext* context, ETextDecoration ASSERT(svgDecorationStyle); bool hasDecorationFill = svgDecorationStyle->hasFill(); - bool hasDecorationStroke = svgDecorationStyle->hasStroke(); + bool hasVisibleDecorationStroke = svgDecorationStyle->hasVisibleStroke(); if (hasDecorationFill) { m_paintingResourceMode = ApplyToFillMode; paintDecorationWithStyle(context, decoration, fragment, decorationRenderer); } - if (hasDecorationStroke) { + if (hasVisibleDecorationStroke) { m_paintingResourceMode = ApplyToStrokeMode; paintDecorationWithStyle(context, decoration, fragment, decorationRenderer); } diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.h b/Source/WebCore/rendering/svg/SVGInlineTextBox.h index 4d0c048bd..d3b9d799d 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.h +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.h @@ -47,7 +47,7 @@ public: void paintSelectionBackground(PaintInfo&); virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); - virtual IntRect localSelectionRect(int startPosition, int endPosition); + virtual LayoutRect localSelectionRect(int startPosition, int endPosition); bool mapStartEndPositionsIntoFragmentCoordinates(const SVGTextFragment&, int& startPosition, int& endPosition) const; @@ -57,6 +57,8 @@ public: Vector<SVGTextFragment>& textFragments() { return m_textFragments; } const Vector<SVGTextFragment>& textFragments() const { return m_textFragments; } + void dirtyLineBoxes() OVERRIDE; + bool startsNewTextChunk() const { return m_startsNewTextChunk; } void setStartsNewTextChunk(bool newTextChunk) { m_startsNewTextChunk = newTextChunk; } diff --git a/Source/WebCore/rendering/svg/SVGPathData.cpp b/Source/WebCore/rendering/svg/SVGPathData.cpp index 15a2551d7..98c80b22f 100644 --- a/Source/WebCore/rendering/svg/SVGPathData.cpp +++ b/Source/WebCore/rendering/svg/SVGPathData.cpp @@ -21,12 +21,13 @@ #include "SVGPathData.h" #if ENABLE(SVG) +#include "Path.h" #include "SVGCircleElement.h" #include "SVGEllipseElement.h" #include "SVGLineElement.h" #include "SVGNames.h" #include "SVGPathElement.h" -#include "SVGPathParserFactory.h" +#include "SVGPathUtilities.h" #include "SVGPolygonElement.h" #include "SVGPolylineElement.h" #include "SVGRectElement.h" @@ -73,7 +74,7 @@ static void updatePathFromLineElement(SVGElement* element, Path& path) static void updatePathFromPathElement(SVGElement* element, Path& path) { ASSERT(element->hasTagName(SVGNames::pathTag)); - SVGPathParserFactory::self()->buildPathFromByteStream(static_cast<SVGPathElement*>(element)->pathByteStream(), path); + buildPathFromByteStream(static_cast<SVGPathElement*>(element)->pathByteStream(), path); } static void updatePathFromPolygonElement(SVGElement* element, Path& path) @@ -133,7 +134,10 @@ static void updatePathFromRectElement(SVGElement* element, Path& path) rx = ry; else if (!hasRy) ry = rx; - path.addRoundedRect(FloatRect(x, y, width, height), FloatSize(rx, ry)); + // FIXME: We currently enforce using beziers here, as at least on CoreGraphics/Lion, as + // the native method uses a different line dash origin, causing svg/custom/dashOrigin.svg to fail. + // See bug https://bugs.webkit.org/show_bug.cgi?id=79932 which tracks this issue. + path.addRoundedRect(FloatRect(x, y, width, height), FloatSize(rx, ry), Path::PreferBezierRoundedRect); return; } diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp index e262422ad..b206cb6c2 100644 --- a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp @@ -73,35 +73,50 @@ void SVGRenderSupport::computeFloatRectForRepaint(const RenderObject* object, Re void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, RenderBoxModelObject* repaintContainer, TransformState& transformState, bool* wasFixed) { transformState.applyTransform(object->localToParentTransform()); - object->parent()->mapLocalToContainer(repaintContainer, false, true, transformState, wasFixed); + + RenderObject* parent = object->parent(); + + // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform + // to map an element from SVG viewport coordinates to CSS box coordinates. + // RenderSVGRoot's mapLocalToContainer method expects CSS box coordinates. + if (parent->isSVGRoot()) + transformState.applyTransform(toRenderSVGRoot(parent)->localToBorderBoxTransform()); + + parent->mapLocalToContainer(repaintContainer, false, true, transformState, RenderObject::DoNotApplyContainerFlip, wasFixed); } -void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox) +// Update a bounding box taking into account the validity of the other bounding box. +static inline void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox) { - bool isFirstChild = true; + bool otherValid = other->isSVGContainer() ? toRenderSVGContainer(other)->isObjectBoundingBoxValid() : true; + if (!otherValid) + return; + + if (!objectBoundingBoxValid) { + objectBoundingBox = otherBoundingBox; + objectBoundingBoxValid = true; + return; + } + objectBoundingBox.uniteEvenIfEmpty(otherBoundingBox); +} + +void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox) +{ for (RenderObject* current = container->firstChild(); current; current = current->nextSibling()) { if (current->isSVGHiddenContainer()) continue; const AffineTransform& transform = current->localToParentTransform(); if (transform.isIdentity()) { - if (isFirstChild) - objectBoundingBox = current->objectBoundingBox(); - else - objectBoundingBox.uniteEvenIfEmpty(current->objectBoundingBox()); + updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, current->objectBoundingBox()); strokeBoundingBox.unite(current->strokeBoundingBox()); repaintBoundingBox.unite(current->repaintRectInLocalCoordinates()); } else { - if (isFirstChild) - objectBoundingBox = transform.mapRect(current->objectBoundingBox()); - else - objectBoundingBox.uniteEvenIfEmpty(transform.mapRect(current->objectBoundingBox())); + updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, transform.mapRect(current->objectBoundingBox())); strokeBoundingBox.unite(transform.mapRect(current->strokeBoundingBox())); repaintBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoordinates())); } - - isFirstChild = false; } } @@ -191,7 +206,7 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) } if (needsLayout) { - child->setNeedsLayout(true, false); + child->setNeedsLayout(true, MarkOnlyThis); child->layout(); } else { if (child->needsLayout()) @@ -219,7 +234,7 @@ bool SVGRenderSupport::isOverflowHidden(const RenderObject* object) // SVG doesn't support independent x/y overflow ASSERT(object->style()->overflowX() == object->style()->overflowY()); - // OSCROLL is never set for SVG - see CSSStyleSelector::adjustRenderStyle + // OSCROLL is never set for SVG - see StyleResolver::adjustRenderStyle ASSERT(object->style()->overflowX() != OSCROLL); // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size. diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.h b/Source/WebCore/rendering/svg/SVGRenderSupport.h index 51c9d1bc0..e25b12f06 100644 --- a/Source/WebCore/rendering/svg/SVGRenderSupport.h +++ b/Source/WebCore/rendering/svg/SVGRenderSupport.h @@ -57,7 +57,7 @@ public: // Determines whether the passed point lies in a clipping area static bool pointInClippingArea(RenderObject*, const FloatPoint&); - static void computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox); + static void computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox); static bool paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo&); // Important functions used by nearly all SVG renderers centralizing coordinate transformations / repaint rect calculations diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp index 8db295f38..966dd46b1 100755 --- a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp @@ -65,7 +65,7 @@ #include "SVGLinearGradientElement.h" #include "SVGNames.h" #include "SVGPathElement.h" -#include "SVGPathParserFactory.h" +#include "SVGPathUtilities.h" #include "SVGPatternElement.h" #include "SVGPointList.h" #include "SVGPolyElement.h" @@ -326,7 +326,7 @@ static void writeStyle(TextStream& ts, const RenderObject& object) static TextStream& writePositionAndStyle(TextStream& ts, const RenderObject& object) { - ts << " " << const_cast<RenderObject&>(object).absoluteClippedOverflowRect(); + ts << " " << enclosingIntRect(const_cast<RenderObject&>(object).absoluteClippedOverflowRect()); writeStyle(ts, object); return ts; } @@ -369,7 +369,7 @@ static TextStream& operator<<(TextStream& ts, const RenderSVGShape& shape) SVGPathElement* element = static_cast<SVGPathElement*>(svgElement); String pathString; // FIXME: We should switch to UnalteredParsing here - this will affect the path dumping output of dozens of tests. - SVGPathParserFactory::self()->buildStringFromByteStream(element->pathByteStream(), pathString, NormalizedParsing); + buildStringFromByteStream(element->pathByteStream(), pathString, NormalizedParsing); writeNameAndQuotedValue(ts, "data", pathString); } else ASSERT_NOT_REACHED(); @@ -443,9 +443,9 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB else ts << " width " << fragment.width; - if (!textBox->isLeftToRightDirection() || textBox->m_dirOverride) { + if (!textBox->isLeftToRightDirection() || textBox->dirOverride()) { ts << (textBox->isLeftToRightDirection() ? " LTR" : " RTL"); - if (textBox->m_dirOverride) + if (textBox->dirOverride()) ts << " override"; } diff --git a/Source/WebCore/rendering/svg/SVGRenderingContext.cpp b/Source/WebCore/rendering/svg/SVGRenderingContext.cpp index 0f13dcf3a..80f53ef17 100644 --- a/Source/WebCore/rendering/svg/SVGRenderingContext.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderingContext.cpp @@ -33,10 +33,11 @@ #include "RenderSVGResourceClipper.h" #include "RenderSVGResourceFilter.h" #include "RenderSVGResourceMasker.h" -#include "SVGImageBufferTools.h" #include "SVGResources.h" #include "SVGResourcesCache.h" +static int kMaxImageBufferSize = 4096; + namespace WebCore { static inline bool isRenderingMaskImage(RenderObject* object) @@ -160,6 +161,134 @@ void SVGRenderingContext::prepareToRenderSVGContent(RenderObject* object, PaintI m_renderingFlags |= RenderingPrepared; } +static AffineTransform& currentContentTransformation() +{ + DEFINE_STATIC_LOCAL(AffineTransform, s_currentContentTransformation, ()); + return s_currentContentTransformation; +} + +void SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform) +{ + const RenderObject* current = renderer; + ASSERT(current); + + absoluteTransform = currentContentTransformation(); + while (current) { + absoluteTransform = current->localToParentTransform() * absoluteTransform; + if (current->isSVGRoot()) + break; + current = current->parent(); + } +} + +bool SVGRenderingContext::createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, OwnPtr<ImageBuffer>& imageBuffer, ColorSpace colorSpace, RenderingMode renderingMode) +{ + IntRect paintRect = calculateImageBufferRect(targetRect, absoluteTransform); + // Don't create empty ImageBuffers. + if (paintRect.isEmpty()) + return false; + + IntSize clampedSize = clampedAbsoluteSize(paintRect.size()); + OwnPtr<ImageBuffer> image = ImageBuffer::create(clampedSize, 1, colorSpace, renderingMode); + if (!image) + return false; + + GraphicsContext* imageContext = image->context(); + ASSERT(imageContext); + + // This is done in absolute coordinates. + imageContext->translate(-paintRect.x(), -paintRect.y()); + + imageContext->concatCTM(absoluteTransform); + + // This happens in local coordinates. + imageContext->scale(FloatSize(static_cast<float>(clampedSize.width()) / paintRect.width(), + static_cast<float>(clampedSize.height()) / paintRect.height())); + + imageBuffer = image.release(); + return true; +} + +bool SVGRenderingContext::createImageBufferForPattern(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>& imageBuffer, ColorSpace colorSpace, RenderingMode renderingMode) +{ + IntSize imageSize(roundedIntSize(clampedAbsoluteTargetRect.size())); + IntSize unclampedImageSize(roundedIntSize(absoluteTargetRect.size())); + + // Don't create empty ImageBuffers. + if (imageSize.isEmpty()) + return false; + + OwnPtr<ImageBuffer> image = ImageBuffer::create(imageSize, 1, colorSpace, renderingMode); + if (!image) + return false; + + GraphicsContext* imageContext = image->context(); + ASSERT(imageContext); + + // Compensate rounding effects, as the absolute target rect is using floating-point numbers and the image buffer size is integer. + imageContext->scale(FloatSize(unclampedImageSize.width() / absoluteTargetRect.width(), unclampedImageSize.height() / absoluteTargetRect.height())); + + imageBuffer = image.release(); + return true; +} + +void SVGRenderingContext::renderSubtreeToImageBuffer(ImageBuffer* image, RenderObject* item, const AffineTransform& subtreeContentTransformation) +{ + ASSERT(item); + ASSERT(image); + ASSERT(image->context()); + + PaintInfo info(image->context(), PaintInfo::infiniteRect(), PaintPhaseForeground, 0, 0, 0, 0); + + AffineTransform& contentTransformation = currentContentTransformation(); + AffineTransform savedContentTransformation = contentTransformation; + contentTransformation = subtreeContentTransformation * contentTransformation; + + ASSERT(!item->needsLayout()); + item->paint(info, IntPoint()); + + contentTransformation = savedContentTransformation; +} + +void SVGRenderingContext::clipToImageBuffer(GraphicsContext* context, const AffineTransform& absoluteTransform, const FloatRect& targetRect, OwnPtr<ImageBuffer>& imageBuffer, bool safeToClear) +{ + ASSERT(context); + ASSERT(imageBuffer); + + FloatRect absoluteTargetRect = calculateImageBufferRect(targetRect, absoluteTransform); + + // The mask image has been created in the absolute coordinate space, as the image should not be scaled. + // So the actual masking process has to be done in the absolute coordinate space as well. + context->concatCTM(absoluteTransform.inverse()); + context->clipToImageBuffer(imageBuffer.get(), absoluteTargetRect); + context->concatCTM(absoluteTransform); + + // When nesting resources, with objectBoundingBox as content unit types, there's no use in caching the + // resulting image buffer as the parent resource already caches the result. + if (safeToClear && !currentContentTransformation().isIdentity()) + imageBuffer.clear(); +} + +FloatRect SVGRenderingContext::clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect) +{ + const FloatSize maxImageBufferSize(kMaxImageBufferSize, kMaxImageBufferSize); + return FloatRect(absoluteTargetRect.location(), absoluteTargetRect.size().shrunkTo(maxImageBufferSize)); +} + +IntSize SVGRenderingContext::clampedAbsoluteSize(const IntSize& absoluteSize) +{ + const IntSize maxImageBufferSize(kMaxImageBufferSize, kMaxImageBufferSize); + return absoluteSize.shrunkTo(maxImageBufferSize); +} + +void SVGRenderingContext::clear2DRotation(AffineTransform& transform) +{ + AffineTransform::DecomposedType decomposition; + transform.decompose(decomposition); + decomposition.angle = 0; + transform.recompose(decomposition); +} + } #endif diff --git a/Source/WebCore/rendering/svg/SVGRenderingContext.h b/Source/WebCore/rendering/svg/SVGRenderingContext.h index 1dc3d6220..4649d9ab7 100644 --- a/Source/WebCore/rendering/svg/SVGRenderingContext.h +++ b/Source/WebCore/rendering/svg/SVGRenderingContext.h @@ -76,6 +76,23 @@ public: void prepareToRenderSVGContent(RenderObject*, PaintInfo&, NeedsGraphicsContextSave = DontSaveGraphicsContext); bool isRenderingPrepared() const { return m_renderingFlags & RenderingPrepared; } + static bool createImageBuffer(const FloatRect& paintRect, const AffineTransform& absoluteTransform, OwnPtr<ImageBuffer>&, ColorSpace, RenderingMode); + // Patterns need a different float-to-integer coordinate mapping. + static bool createImageBufferForPattern(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, OwnPtr<ImageBuffer>&, ColorSpace, RenderingMode); + + static void renderSubtreeToImageBuffer(ImageBuffer*, RenderObject*, const AffineTransform&); + static void clipToImageBuffer(GraphicsContext*, const AffineTransform& absoluteTransform, const FloatRect& targetRect, OwnPtr<ImageBuffer>&, bool safeToClear); + + static void calculateTransformationToOutermostSVGCoordinateSystem(const RenderObject*, AffineTransform& absoluteTransform); + static IntSize clampedAbsoluteSize(const IntSize&); + static FloatRect clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect); + static void clear2DRotation(AffineTransform&); + + static IntRect calculateImageBufferRect(const FloatRect& targetRect, const AffineTransform& absoluteTransform) + { + return enclosingIntRect(absoluteTransform.mapRect(targetRect)); + } + private: // To properly revert partially successful initializtions in the destructor, we record all successful steps. enum RenderingFlags { |